Home | History | Annotate | Download | only in androidfw
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #define LOG_TAG "ResourceType"
     18 //#define LOG_NDEBUG 0
     19 
     20 #include <ctype.h>
     21 #include <memory.h>
     22 #include <stddef.h>
     23 #include <stdint.h>
     24 #include <stdlib.h>
     25 #include <string.h>
     26 
     27 #include <limits>
     28 #include <type_traits>
     29 
     30 #include <androidfw/ByteBucketArray.h>
     31 #include <androidfw/ResourceTypes.h>
     32 #include <androidfw/TypeWrappers.h>
     33 #include <utils/Atomic.h>
     34 #include <utils/ByteOrder.h>
     35 #include <utils/Debug.h>
     36 #include <utils/Log.h>
     37 #include <utils/String16.h>
     38 #include <utils/String8.h>
     39 
     40 #ifdef __ANDROID__
     41 #include <binder/TextOutput.h>
     42 #endif
     43 
     44 #ifndef INT32_MAX
     45 #define INT32_MAX ((int32_t)(2147483647))
     46 #endif
     47 
     48 namespace android {
     49 
     50 #ifdef HAVE_WINSOCK
     51 #undef  nhtol
     52 #undef  htonl
     53 #define ntohl(x)    ( ((x) << 24) | (((x) >> 24) & 255) | (((x) << 8) & 0xff0000) | (((x) >> 8) & 0xff00) )
     54 #define htonl(x)    ntohl(x)
     55 #define ntohs(x)    ( (((x) << 8) & 0xff00) | (((x) >> 8) & 255) )
     56 #define htons(x)    ntohs(x)
     57 #endif
     58 
     59 #define IDMAP_MAGIC             0x504D4449
     60 #define IDMAP_CURRENT_VERSION   0x00000001
     61 
     62 #define APP_PACKAGE_ID      0x7f
     63 #define SYS_PACKAGE_ID      0x01
     64 
     65 static const bool kDebugStringPoolNoisy = false;
     66 static const bool kDebugXMLNoisy = false;
     67 static const bool kDebugTableNoisy = false;
     68 static const bool kDebugTableGetEntry = false;
     69 static const bool kDebugTableSuperNoisy = false;
     70 static const bool kDebugLoadTableNoisy = false;
     71 static const bool kDebugLoadTableSuperNoisy = false;
     72 static const bool kDebugTableTheme = false;
     73 static const bool kDebugResXMLTree = false;
     74 static const bool kDebugLibNoisy = false;
     75 
     76 // TODO: This code uses 0xFFFFFFFF converted to bag_set* as a sentinel value. This is bad practice.
     77 
     78 // Standard C isspace() is only required to look at the low byte of its input, so
     79 // produces incorrect results for UTF-16 characters.  For safety's sake, assume that
     80 // any high-byte UTF-16 code point is not whitespace.
     81 inline int isspace16(char16_t c) {
     82     return (c < 0x0080 && isspace(c));
     83 }
     84 
     85 template<typename T>
     86 inline static T max(T a, T b) {
     87     return a > b ? a : b;
     88 }
     89 
     90 // range checked; guaranteed to NUL-terminate within the stated number of available slots
     91 // NOTE: if this truncates the dst string due to running out of space, no attempt is
     92 // made to avoid splitting surrogate pairs.
     93 static void strcpy16_dtoh(char16_t* dst, const uint16_t* src, size_t avail)
     94 {
     95     char16_t* last = dst + avail - 1;
     96     while (*src && (dst < last)) {
     97         char16_t s = dtohs(static_cast<char16_t>(*src));
     98         *dst++ = s;
     99         src++;
    100     }
    101     *dst = 0;
    102 }
    103 
    104 static status_t validate_chunk(const ResChunk_header* chunk,
    105                                size_t minSize,
    106                                const uint8_t* dataEnd,
    107                                const char* name)
    108 {
    109     const uint16_t headerSize = dtohs(chunk->headerSize);
    110     const uint32_t size = dtohl(chunk->size);
    111 
    112     if (headerSize >= minSize) {
    113         if (headerSize <= size) {
    114             if (((headerSize|size)&0x3) == 0) {
    115                 if ((size_t)size <= (size_t)(dataEnd-((const uint8_t*)chunk))) {
    116                     return NO_ERROR;
    117                 }
    118                 ALOGW("%s data size 0x%x extends beyond resource end %p.",
    119                      name, size, (void*)(dataEnd-((const uint8_t*)chunk)));
    120                 return BAD_TYPE;
    121             }
    122             ALOGW("%s size 0x%x or headerSize 0x%x is not on an integer boundary.",
    123                  name, (int)size, (int)headerSize);
    124             return BAD_TYPE;
    125         }
    126         ALOGW("%s size 0x%x is smaller than header size 0x%x.",
    127              name, size, headerSize);
    128         return BAD_TYPE;
    129     }
    130     ALOGW("%s header size 0x%04x is too small.",
    131          name, headerSize);
    132     return BAD_TYPE;
    133 }
    134 
    135 static void fill9patchOffsets(Res_png_9patch* patch) {
    136     patch->xDivsOffset = sizeof(Res_png_9patch);
    137     patch->yDivsOffset = patch->xDivsOffset + (patch->numXDivs * sizeof(int32_t));
    138     patch->colorsOffset = patch->yDivsOffset + (patch->numYDivs * sizeof(int32_t));
    139 }
    140 
    141 inline void Res_value::copyFrom_dtoh(const Res_value& src)
    142 {
    143     size = dtohs(src.size);
    144     res0 = src.res0;
    145     dataType = src.dataType;
    146     data = dtohl(src.data);
    147 }
    148 
    149 void Res_png_9patch::deviceToFile()
    150 {
    151     int32_t* xDivs = getXDivs();
    152     for (int i = 0; i < numXDivs; i++) {
    153         xDivs[i] = htonl(xDivs[i]);
    154     }
    155     int32_t* yDivs = getYDivs();
    156     for (int i = 0; i < numYDivs; i++) {
    157         yDivs[i] = htonl(yDivs[i]);
    158     }
    159     paddingLeft = htonl(paddingLeft);
    160     paddingRight = htonl(paddingRight);
    161     paddingTop = htonl(paddingTop);
    162     paddingBottom = htonl(paddingBottom);
    163     uint32_t* colors = getColors();
    164     for (int i=0; i<numColors; i++) {
    165         colors[i] = htonl(colors[i]);
    166     }
    167 }
    168 
    169 void Res_png_9patch::fileToDevice()
    170 {
    171     int32_t* xDivs = getXDivs();
    172     for (int i = 0; i < numXDivs; i++) {
    173         xDivs[i] = ntohl(xDivs[i]);
    174     }
    175     int32_t* yDivs = getYDivs();
    176     for (int i = 0; i < numYDivs; i++) {
    177         yDivs[i] = ntohl(yDivs[i]);
    178     }
    179     paddingLeft = ntohl(paddingLeft);
    180     paddingRight = ntohl(paddingRight);
    181     paddingTop = ntohl(paddingTop);
    182     paddingBottom = ntohl(paddingBottom);
    183     uint32_t* colors = getColors();
    184     for (int i=0; i<numColors; i++) {
    185         colors[i] = ntohl(colors[i]);
    186     }
    187 }
    188 
    189 size_t Res_png_9patch::serializedSize() const
    190 {
    191     // The size of this struct is 32 bytes on the 32-bit target system
    192     // 4 * int8_t
    193     // 4 * int32_t
    194     // 3 * uint32_t
    195     return 32
    196             + numXDivs * sizeof(int32_t)
    197             + numYDivs * sizeof(int32_t)
    198             + numColors * sizeof(uint32_t);
    199 }
    200 
    201 void* Res_png_9patch::serialize(const Res_png_9patch& patch, const int32_t* xDivs,
    202                                 const int32_t* yDivs, const uint32_t* colors)
    203 {
    204     // Use calloc since we're going to leave a few holes in the data
    205     // and want this to run cleanly under valgrind
    206     void* newData = calloc(1, patch.serializedSize());
    207     serialize(patch, xDivs, yDivs, colors, newData);
    208     return newData;
    209 }
    210 
    211 void Res_png_9patch::serialize(const Res_png_9patch& patch, const int32_t* xDivs,
    212                                const int32_t* yDivs, const uint32_t* colors, void* outData)
    213 {
    214     uint8_t* data = (uint8_t*) outData;
    215     memcpy(data, &patch.wasDeserialized, 4);     // copy  wasDeserialized, numXDivs, numYDivs, numColors
    216     memcpy(data + 12, &patch.paddingLeft, 16);   // copy paddingXXXX
    217     data += 32;
    218 
    219     memcpy(data, xDivs, patch.numXDivs * sizeof(int32_t));
    220     data +=  patch.numXDivs * sizeof(int32_t);
    221     memcpy(data, yDivs, patch.numYDivs * sizeof(int32_t));
    222     data +=  patch.numYDivs * sizeof(int32_t);
    223     memcpy(data, colors, patch.numColors * sizeof(uint32_t));
    224 
    225     fill9patchOffsets(reinterpret_cast<Res_png_9patch*>(outData));
    226 }
    227 
    228 static bool assertIdmapHeader(const void* idmap, size_t size) {
    229     if (reinterpret_cast<uintptr_t>(idmap) & 0x03) {
    230         ALOGE("idmap: header is not word aligned");
    231         return false;
    232     }
    233 
    234     if (size < ResTable::IDMAP_HEADER_SIZE_BYTES) {
    235         ALOGW("idmap: header too small (%d bytes)", (uint32_t) size);
    236         return false;
    237     }
    238 
    239     const uint32_t magic = htodl(*reinterpret_cast<const uint32_t*>(idmap));
    240     if (magic != IDMAP_MAGIC) {
    241         ALOGW("idmap: no magic found in header (is 0x%08x, expected 0x%08x)",
    242              magic, IDMAP_MAGIC);
    243         return false;
    244     }
    245 
    246     const uint32_t version = htodl(*(reinterpret_cast<const uint32_t*>(idmap) + 1));
    247     if (version != IDMAP_CURRENT_VERSION) {
    248         // We are strict about versions because files with this format are
    249         // auto-generated and don't need backwards compatibility.
    250         ALOGW("idmap: version mismatch in header (is 0x%08x, expected 0x%08x)",
    251                 version, IDMAP_CURRENT_VERSION);
    252         return false;
    253     }
    254     return true;
    255 }
    256 
    257 class IdmapEntries {
    258 public:
    259     IdmapEntries() : mData(NULL) {}
    260 
    261     bool hasEntries() const {
    262         if (mData == NULL) {
    263             return false;
    264         }
    265 
    266         return (dtohs(*mData) > 0);
    267     }
    268 
    269     size_t byteSize() const {
    270         if (mData == NULL) {
    271             return 0;
    272         }
    273         uint16_t entryCount = dtohs(mData[2]);
    274         return (sizeof(uint16_t) * 4) + (sizeof(uint32_t) * static_cast<size_t>(entryCount));
    275     }
    276 
    277     uint8_t targetTypeId() const {
    278         if (mData == NULL) {
    279             return 0;
    280         }
    281         return dtohs(mData[0]);
    282     }
    283 
    284     uint8_t overlayTypeId() const {
    285         if (mData == NULL) {
    286             return 0;
    287         }
    288         return dtohs(mData[1]);
    289     }
    290 
    291     status_t setTo(const void* entryHeader, size_t size) {
    292         if (reinterpret_cast<uintptr_t>(entryHeader) & 0x03) {
    293             ALOGE("idmap: entry header is not word aligned");
    294             return UNKNOWN_ERROR;
    295         }
    296 
    297         if (size < sizeof(uint16_t) * 4) {
    298             ALOGE("idmap: entry header is too small (%u bytes)", (uint32_t) size);
    299             return UNKNOWN_ERROR;
    300         }
    301 
    302         const uint16_t* header = reinterpret_cast<const uint16_t*>(entryHeader);
    303         const uint16_t targetTypeId = dtohs(header[0]);
    304         const uint16_t overlayTypeId = dtohs(header[1]);
    305         if (targetTypeId == 0 || overlayTypeId == 0 || targetTypeId > 255 || overlayTypeId > 255) {
    306             ALOGE("idmap: invalid type map (%u -> %u)", targetTypeId, overlayTypeId);
    307             return UNKNOWN_ERROR;
    308         }
    309 
    310         uint16_t entryCount = dtohs(header[2]);
    311         if (size < sizeof(uint32_t) * (entryCount + 2)) {
    312             ALOGE("idmap: too small (%u bytes) for the number of entries (%u)",
    313                     (uint32_t) size, (uint32_t) entryCount);
    314             return UNKNOWN_ERROR;
    315         }
    316         mData = header;
    317         return NO_ERROR;
    318     }
    319 
    320     status_t lookup(uint16_t entryId, uint16_t* outEntryId) const {
    321         uint16_t entryCount = dtohs(mData[2]);
    322         uint16_t offset = dtohs(mData[3]);
    323 
    324         if (entryId < offset) {
    325             // The entry is not present in this idmap
    326             return BAD_INDEX;
    327         }
    328 
    329         entryId -= offset;
    330 
    331         if (entryId >= entryCount) {
    332             // The entry is not present in this idmap
    333             return BAD_INDEX;
    334         }
    335 
    336         // It is safe to access the type here without checking the size because
    337         // we have checked this when it was first loaded.
    338         const uint32_t* entries = reinterpret_cast<const uint32_t*>(mData) + 2;
    339         uint32_t mappedEntry = dtohl(entries[entryId]);
    340         if (mappedEntry == 0xffffffff) {
    341             // This entry is not present in this idmap
    342             return BAD_INDEX;
    343         }
    344         *outEntryId = static_cast<uint16_t>(mappedEntry);
    345         return NO_ERROR;
    346     }
    347 
    348 private:
    349     const uint16_t* mData;
    350 };
    351 
    352 status_t parseIdmap(const void* idmap, size_t size, uint8_t* outPackageId, KeyedVector<uint8_t, IdmapEntries>* outMap) {
    353     if (!assertIdmapHeader(idmap, size)) {
    354         return UNKNOWN_ERROR;
    355     }
    356 
    357     size -= ResTable::IDMAP_HEADER_SIZE_BYTES;
    358     if (size < sizeof(uint16_t) * 2) {
    359         ALOGE("idmap: too small to contain any mapping");
    360         return UNKNOWN_ERROR;
    361     }
    362 
    363     const uint16_t* data = reinterpret_cast<const uint16_t*>(
    364             reinterpret_cast<const uint8_t*>(idmap) + ResTable::IDMAP_HEADER_SIZE_BYTES);
    365 
    366     uint16_t targetPackageId = dtohs(*(data++));
    367     if (targetPackageId == 0 || targetPackageId > 255) {
    368         ALOGE("idmap: target package ID is invalid (%02x)", targetPackageId);
    369         return UNKNOWN_ERROR;
    370     }
    371 
    372     uint16_t mapCount = dtohs(*(data++));
    373     if (mapCount == 0) {
    374         ALOGE("idmap: no mappings");
    375         return UNKNOWN_ERROR;
    376     }
    377 
    378     if (mapCount > 255) {
    379         ALOGW("idmap: too many mappings. Only 255 are possible but %u are present", (uint32_t) mapCount);
    380     }
    381 
    382     while (size > sizeof(uint16_t) * 4) {
    383         IdmapEntries entries;
    384         status_t err = entries.setTo(data, size);
    385         if (err != NO_ERROR) {
    386             return err;
    387         }
    388 
    389         ssize_t index = outMap->add(entries.overlayTypeId(), entries);
    390         if (index < 0) {
    391             return NO_MEMORY;
    392         }
    393 
    394         data += entries.byteSize() / sizeof(uint16_t);
    395         size -= entries.byteSize();
    396     }
    397 
    398     if (outPackageId != NULL) {
    399         *outPackageId = static_cast<uint8_t>(targetPackageId);
    400     }
    401     return NO_ERROR;
    402 }
    403 
    404 Res_png_9patch* Res_png_9patch::deserialize(void* inData)
    405 {
    406 
    407     Res_png_9patch* patch = reinterpret_cast<Res_png_9patch*>(inData);
    408     patch->wasDeserialized = true;
    409     fill9patchOffsets(patch);
    410 
    411     return patch;
    412 }
    413 
    414 // --------------------------------------------------------------------
    415 // --------------------------------------------------------------------
    416 // --------------------------------------------------------------------
    417 
    418 ResStringPool::ResStringPool()
    419     : mError(NO_INIT), mOwnedData(NULL), mHeader(NULL), mCache(NULL)
    420 {
    421 }
    422 
    423 ResStringPool::ResStringPool(const void* data, size_t size, bool copyData)
    424     : mError(NO_INIT), mOwnedData(NULL), mHeader(NULL), mCache(NULL)
    425 {
    426     setTo(data, size, copyData);
    427 }
    428 
    429 ResStringPool::~ResStringPool()
    430 {
    431     uninit();
    432 }
    433 
    434 void ResStringPool::setToEmpty()
    435 {
    436     uninit();
    437 
    438     mOwnedData = calloc(1, sizeof(ResStringPool_header));
    439     ResStringPool_header* header = (ResStringPool_header*) mOwnedData;
    440     mSize = 0;
    441     mEntries = NULL;
    442     mStrings = NULL;
    443     mStringPoolSize = 0;
    444     mEntryStyles = NULL;
    445     mStyles = NULL;
    446     mStylePoolSize = 0;
    447     mHeader = (const ResStringPool_header*) header;
    448 }
    449 
    450 status_t ResStringPool::setTo(const void* data, size_t size, bool copyData)
    451 {
    452     if (!data || !size) {
    453         return (mError=BAD_TYPE);
    454     }
    455 
    456     uninit();
    457 
    458     const bool notDeviceEndian = htods(0xf0) != 0xf0;
    459 
    460     if (copyData || notDeviceEndian) {
    461         mOwnedData = malloc(size);
    462         if (mOwnedData == NULL) {
    463             return (mError=NO_MEMORY);
    464         }
    465         memcpy(mOwnedData, data, size);
    466         data = mOwnedData;
    467     }
    468 
    469     mHeader = (const ResStringPool_header*)data;
    470 
    471     if (notDeviceEndian) {
    472         ResStringPool_header* h = const_cast<ResStringPool_header*>(mHeader);
    473         h->header.headerSize = dtohs(mHeader->header.headerSize);
    474         h->header.type = dtohs(mHeader->header.type);
    475         h->header.size = dtohl(mHeader->header.size);
    476         h->stringCount = dtohl(mHeader->stringCount);
    477         h->styleCount = dtohl(mHeader->styleCount);
    478         h->flags = dtohl(mHeader->flags);
    479         h->stringsStart = dtohl(mHeader->stringsStart);
    480         h->stylesStart = dtohl(mHeader->stylesStart);
    481     }
    482 
    483     if (mHeader->header.headerSize > mHeader->header.size
    484             || mHeader->header.size > size) {
    485         ALOGW("Bad string block: header size %d or total size %d is larger than data size %d\n",
    486                 (int)mHeader->header.headerSize, (int)mHeader->header.size, (int)size);
    487         return (mError=BAD_TYPE);
    488     }
    489     mSize = mHeader->header.size;
    490     mEntries = (const uint32_t*)
    491         (((const uint8_t*)data)+mHeader->header.headerSize);
    492 
    493     if (mHeader->stringCount > 0) {
    494         if ((mHeader->stringCount*sizeof(uint32_t) < mHeader->stringCount)  // uint32 overflow?
    495             || (mHeader->header.headerSize+(mHeader->stringCount*sizeof(uint32_t)))
    496                 > size) {
    497             ALOGW("Bad string block: entry of %d items extends past data size %d\n",
    498                     (int)(mHeader->header.headerSize+(mHeader->stringCount*sizeof(uint32_t))),
    499                     (int)size);
    500             return (mError=BAD_TYPE);
    501         }
    502 
    503         size_t charSize;
    504         if (mHeader->flags&ResStringPool_header::UTF8_FLAG) {
    505             charSize = sizeof(uint8_t);
    506         } else {
    507             charSize = sizeof(uint16_t);
    508         }
    509 
    510         // There should be at least space for the smallest string
    511         // (2 bytes length, null terminator).
    512         if (mHeader->stringsStart >= (mSize - sizeof(uint16_t))) {
    513             ALOGW("Bad string block: string pool starts at %d, after total size %d\n",
    514                     (int)mHeader->stringsStart, (int)mHeader->header.size);
    515             return (mError=BAD_TYPE);
    516         }
    517 
    518         mStrings = (const void*)
    519             (((const uint8_t*)data) + mHeader->stringsStart);
    520 
    521         if (mHeader->styleCount == 0) {
    522             mStringPoolSize = (mSize - mHeader->stringsStart) / charSize;
    523         } else {
    524             // check invariant: styles starts before end of data
    525             if (mHeader->stylesStart >= (mSize - sizeof(uint16_t))) {
    526                 ALOGW("Bad style block: style block starts at %d past data size of %d\n",
    527                     (int)mHeader->stylesStart, (int)mHeader->header.size);
    528                 return (mError=BAD_TYPE);
    529             }
    530             // check invariant: styles follow the strings
    531             if (mHeader->stylesStart <= mHeader->stringsStart) {
    532                 ALOGW("Bad style block: style block starts at %d, before strings at %d\n",
    533                     (int)mHeader->stylesStart, (int)mHeader->stringsStart);
    534                 return (mError=BAD_TYPE);
    535             }
    536             mStringPoolSize =
    537                 (mHeader->stylesStart-mHeader->stringsStart)/charSize;
    538         }
    539 
    540         // check invariant: stringCount > 0 requires a string pool to exist
    541         if (mStringPoolSize == 0) {
    542             ALOGW("Bad string block: stringCount is %d but pool size is 0\n", (int)mHeader->stringCount);
    543             return (mError=BAD_TYPE);
    544         }
    545 
    546         if (notDeviceEndian) {
    547             size_t i;
    548             uint32_t* e = const_cast<uint32_t*>(mEntries);
    549             for (i=0; i<mHeader->stringCount; i++) {
    550                 e[i] = dtohl(mEntries[i]);
    551             }
    552             if (!(mHeader->flags&ResStringPool_header::UTF8_FLAG)) {
    553                 const uint16_t* strings = (const uint16_t*)mStrings;
    554                 uint16_t* s = const_cast<uint16_t*>(strings);
    555                 for (i=0; i<mStringPoolSize; i++) {
    556                     s[i] = dtohs(strings[i]);
    557                 }
    558             }
    559         }
    560 
    561         if ((mHeader->flags&ResStringPool_header::UTF8_FLAG &&
    562                 ((uint8_t*)mStrings)[mStringPoolSize-1] != 0) ||
    563                 (!mHeader->flags&ResStringPool_header::UTF8_FLAG &&
    564                 ((uint16_t*)mStrings)[mStringPoolSize-1] != 0)) {
    565             ALOGW("Bad string block: last string is not 0-terminated\n");
    566             return (mError=BAD_TYPE);
    567         }
    568     } else {
    569         mStrings = NULL;
    570         mStringPoolSize = 0;
    571     }
    572 
    573     if (mHeader->styleCount > 0) {
    574         mEntryStyles = mEntries + mHeader->stringCount;
    575         // invariant: integer overflow in calculating mEntryStyles
    576         if (mEntryStyles < mEntries) {
    577             ALOGW("Bad string block: integer overflow finding styles\n");
    578             return (mError=BAD_TYPE);
    579         }
    580 
    581         if (((const uint8_t*)mEntryStyles-(const uint8_t*)mHeader) > (int)size) {
    582             ALOGW("Bad string block: entry of %d styles extends past data size %d\n",
    583                     (int)((const uint8_t*)mEntryStyles-(const uint8_t*)mHeader),
    584                     (int)size);
    585             return (mError=BAD_TYPE);
    586         }
    587         mStyles = (const uint32_t*)
    588             (((const uint8_t*)data)+mHeader->stylesStart);
    589         if (mHeader->stylesStart >= mHeader->header.size) {
    590             ALOGW("Bad string block: style pool starts %d, after total size %d\n",
    591                     (int)mHeader->stylesStart, (int)mHeader->header.size);
    592             return (mError=BAD_TYPE);
    593         }
    594         mStylePoolSize =
    595             (mHeader->header.size-mHeader->stylesStart)/sizeof(uint32_t);
    596 
    597         if (notDeviceEndian) {
    598             size_t i;
    599             uint32_t* e = const_cast<uint32_t*>(mEntryStyles);
    600             for (i=0; i<mHeader->styleCount; i++) {
    601                 e[i] = dtohl(mEntryStyles[i]);
    602             }
    603             uint32_t* s = const_cast<uint32_t*>(mStyles);
    604             for (i=0; i<mStylePoolSize; i++) {
    605                 s[i] = dtohl(mStyles[i]);
    606             }
    607         }
    608 
    609         const ResStringPool_span endSpan = {
    610             { htodl(ResStringPool_span::END) },
    611             htodl(ResStringPool_span::END), htodl(ResStringPool_span::END)
    612         };
    613         if (memcmp(&mStyles[mStylePoolSize-(sizeof(endSpan)/sizeof(uint32_t))],
    614                    &endSpan, sizeof(endSpan)) != 0) {
    615             ALOGW("Bad string block: last style is not 0xFFFFFFFF-terminated\n");
    616             return (mError=BAD_TYPE);
    617         }
    618     } else {
    619         mEntryStyles = NULL;
    620         mStyles = NULL;
    621         mStylePoolSize = 0;
    622     }
    623 
    624     return (mError=NO_ERROR);
    625 }
    626 
    627 status_t ResStringPool::getError() const
    628 {
    629     return mError;
    630 }
    631 
    632 void ResStringPool::uninit()
    633 {
    634     mError = NO_INIT;
    635     if (mHeader != NULL && mCache != NULL) {
    636         for (size_t x = 0; x < mHeader->stringCount; x++) {
    637             if (mCache[x] != NULL) {
    638                 free(mCache[x]);
    639                 mCache[x] = NULL;
    640             }
    641         }
    642         free(mCache);
    643         mCache = NULL;
    644     }
    645     if (mOwnedData) {
    646         free(mOwnedData);
    647         mOwnedData = NULL;
    648     }
    649 }
    650 
    651 /**
    652  * Strings in UTF-16 format have length indicated by a length encoded in the
    653  * stored data. It is either 1 or 2 characters of length data. This allows a
    654  * maximum length of 0x7FFFFFF (2147483647 bytes), but if you're storing that
    655  * much data in a string, you're abusing them.
    656  *
    657  * If the high bit is set, then there are two characters or 4 bytes of length
    658  * data encoded. In that case, drop the high bit of the first character and
    659  * add it together with the next character.
    660  */
    661 static inline size_t
    662 decodeLength(const uint16_t** str)
    663 {
    664     size_t len = **str;
    665     if ((len & 0x8000) != 0) {
    666         (*str)++;
    667         len = ((len & 0x7FFF) << 16) | **str;
    668     }
    669     (*str)++;
    670     return len;
    671 }
    672 
    673 /**
    674  * Strings in UTF-8 format have length indicated by a length encoded in the
    675  * stored data. It is either 1 or 2 characters of length data. This allows a
    676  * maximum length of 0x7FFF (32767 bytes), but you should consider storing
    677  * text in another way if you're using that much data in a single string.
    678  *
    679  * If the high bit is set, then there are two characters or 2 bytes of length
    680  * data encoded. In that case, drop the high bit of the first character and
    681  * add it together with the next character.
    682  */
    683 static inline size_t
    684 decodeLength(const uint8_t** str)
    685 {
    686     size_t len = **str;
    687     if ((len & 0x80) != 0) {
    688         (*str)++;
    689         len = ((len & 0x7F) << 8) | **str;
    690     }
    691     (*str)++;
    692     return len;
    693 }
    694 
    695 const char16_t* ResStringPool::stringAt(size_t idx, size_t* u16len) const
    696 {
    697     if (mError == NO_ERROR && idx < mHeader->stringCount) {
    698         const bool isUTF8 = (mHeader->flags&ResStringPool_header::UTF8_FLAG) != 0;
    699         const uint32_t off = mEntries[idx]/(isUTF8?sizeof(uint8_t):sizeof(uint16_t));
    700         if (off < (mStringPoolSize-1)) {
    701             if (!isUTF8) {
    702                 const uint16_t* strings = (uint16_t*)mStrings;
    703                 const uint16_t* str = strings+off;
    704 
    705                 *u16len = decodeLength(&str);
    706                 if ((uint32_t)(str+*u16len-strings) < mStringPoolSize) {
    707                     // Reject malformed (non null-terminated) strings
    708                     if (str[*u16len] != 0x0000) {
    709                         ALOGW("Bad string block: string #%d is not null-terminated",
    710                               (int)idx);
    711                         return NULL;
    712                     }
    713                     return reinterpret_cast<const char16_t*>(str);
    714                 } else {
    715                     ALOGW("Bad string block: string #%d extends to %d, past end at %d\n",
    716                             (int)idx, (int)(str+*u16len-strings), (int)mStringPoolSize);
    717                 }
    718             } else {
    719                 const uint8_t* strings = (uint8_t*)mStrings;
    720                 const uint8_t* u8str = strings+off;
    721 
    722                 *u16len = decodeLength(&u8str);
    723                 size_t u8len = decodeLength(&u8str);
    724 
    725                 // encLen must be less than 0x7FFF due to encoding.
    726                 if ((uint32_t)(u8str+u8len-strings) < mStringPoolSize) {
    727                     AutoMutex lock(mDecodeLock);
    728 
    729                     if (mCache == NULL) {
    730 #ifndef HAVE_ANDROID_OS
    731                         if (kDebugStringPoolNoisy) {
    732                             ALOGI("CREATING STRING CACHE OF %zu bytes",
    733                                     mHeader->stringCount*sizeof(char16_t**));
    734                         }
    735 #else
    736                         // We do not want to be in this case when actually running Android.
    737                         ALOGW("CREATING STRING CACHE OF %zu bytes",
    738                                 static_cast<size_t>(mHeader->stringCount*sizeof(char16_t**)));
    739 #endif
    740                         mCache = (char16_t**)calloc(mHeader->stringCount, sizeof(char16_t**));
    741                         if (mCache == NULL) {
    742                             ALOGW("No memory trying to allocate decode cache table of %d bytes\n",
    743                                     (int)(mHeader->stringCount*sizeof(char16_t**)));
    744                             return NULL;
    745                         }
    746                     }
    747 
    748                     if (mCache[idx] != NULL) {
    749                         return mCache[idx];
    750                     }
    751 
    752                     ssize_t actualLen = utf8_to_utf16_length(u8str, u8len);
    753                     if (actualLen < 0 || (size_t)actualLen != *u16len) {
    754                         ALOGW("Bad string block: string #%lld decoded length is not correct "
    755                                 "%lld vs %llu\n",
    756                                 (long long)idx, (long long)actualLen, (long long)*u16len);
    757                         return NULL;
    758                     }
    759 
    760                     // Reject malformed (non null-terminated) strings
    761                     if (u8str[u8len] != 0x00) {
    762                         ALOGW("Bad string block: string #%d is not null-terminated",
    763                               (int)idx);
    764                         return NULL;
    765                     }
    766 
    767                     char16_t *u16str = (char16_t *)calloc(*u16len+1, sizeof(char16_t));
    768                     if (!u16str) {
    769                         ALOGW("No memory when trying to allocate decode cache for string #%d\n",
    770                                 (int)idx);
    771                         return NULL;
    772                     }
    773 
    774                     if (kDebugStringPoolNoisy) {
    775                         ALOGI("Caching UTF8 string: %s", u8str);
    776                     }
    777                     utf8_to_utf16(u8str, u8len, u16str);
    778                     mCache[idx] = u16str;
    779                     return u16str;
    780                 } else {
    781                     ALOGW("Bad string block: string #%lld extends to %lld, past end at %lld\n",
    782                             (long long)idx, (long long)(u8str+u8len-strings),
    783                             (long long)mStringPoolSize);
    784                 }
    785             }
    786         } else {
    787             ALOGW("Bad string block: string #%d entry is at %d, past end at %d\n",
    788                     (int)idx, (int)(off*sizeof(uint16_t)),
    789                     (int)(mStringPoolSize*sizeof(uint16_t)));
    790         }
    791     }
    792     return NULL;
    793 }
    794 
    795 const char* ResStringPool::string8At(size_t idx, size_t* outLen) const
    796 {
    797     if (mError == NO_ERROR && idx < mHeader->stringCount) {
    798         if ((mHeader->flags&ResStringPool_header::UTF8_FLAG) == 0) {
    799             return NULL;
    800         }
    801         const uint32_t off = mEntries[idx]/sizeof(char);
    802         if (off < (mStringPoolSize-1)) {
    803             const uint8_t* strings = (uint8_t*)mStrings;
    804             const uint8_t* str = strings+off;
    805             *outLen = decodeLength(&str);
    806             size_t encLen = decodeLength(&str);
    807             if ((uint32_t)(str+encLen-strings) < mStringPoolSize) {
    808                 return (const char*)str;
    809             } else {
    810                 ALOGW("Bad string block: string #%d extends to %d, past end at %d\n",
    811                         (int)idx, (int)(str+encLen-strings), (int)mStringPoolSize);
    812             }
    813         } else {
    814             ALOGW("Bad string block: string #%d entry is at %d, past end at %d\n",
    815                     (int)idx, (int)(off*sizeof(uint16_t)),
    816                     (int)(mStringPoolSize*sizeof(uint16_t)));
    817         }
    818     }
    819     return NULL;
    820 }
    821 
    822 const String8 ResStringPool::string8ObjectAt(size_t idx) const
    823 {
    824     size_t len;
    825     const char *str = string8At(idx, &len);
    826     if (str != NULL) {
    827         return String8(str, len);
    828     }
    829 
    830     const char16_t *str16 = stringAt(idx, &len);
    831     if (str16 != NULL) {
    832         return String8(str16, len);
    833     }
    834     return String8();
    835 }
    836 
    837 const ResStringPool_span* ResStringPool::styleAt(const ResStringPool_ref& ref) const
    838 {
    839     return styleAt(ref.index);
    840 }
    841 
    842 const ResStringPool_span* ResStringPool::styleAt(size_t idx) const
    843 {
    844     if (mError == NO_ERROR && idx < mHeader->styleCount) {
    845         const uint32_t off = (mEntryStyles[idx]/sizeof(uint32_t));
    846         if (off < mStylePoolSize) {
    847             return (const ResStringPool_span*)(mStyles+off);
    848         } else {
    849             ALOGW("Bad string block: style #%d entry is at %d, past end at %d\n",
    850                     (int)idx, (int)(off*sizeof(uint32_t)),
    851                     (int)(mStylePoolSize*sizeof(uint32_t)));
    852         }
    853     }
    854     return NULL;
    855 }
    856 
    857 ssize_t ResStringPool::indexOfString(const char16_t* str, size_t strLen) const
    858 {
    859     if (mError != NO_ERROR) {
    860         return mError;
    861     }
    862 
    863     size_t len;
    864 
    865     if ((mHeader->flags&ResStringPool_header::UTF8_FLAG) != 0) {
    866         if (kDebugStringPoolNoisy) {
    867             ALOGI("indexOfString UTF-8: %s", String8(str, strLen).string());
    868         }
    869 
    870         // The string pool contains UTF 8 strings; we don't want to cause
    871         // temporary UTF-16 strings to be created as we search.
    872         if (mHeader->flags&ResStringPool_header::SORTED_FLAG) {
    873             // Do a binary search for the string...  this is a little tricky,
    874             // because the strings are sorted with strzcmp16().  So to match
    875             // the ordering, we need to convert strings in the pool to UTF-16.
    876             // But we don't want to hit the cache, so instead we will have a
    877             // local temporary allocation for the conversions.
    878             char16_t* convBuffer = (char16_t*)malloc(strLen+4);
    879             ssize_t l = 0;
    880             ssize_t h = mHeader->stringCount-1;
    881 
    882             ssize_t mid;
    883             while (l <= h) {
    884                 mid = l + (h - l)/2;
    885                 const uint8_t* s = (const uint8_t*)string8At(mid, &len);
    886                 int c;
    887                 if (s != NULL) {
    888                     char16_t* end = utf8_to_utf16_n(s, len, convBuffer, strLen+3);
    889                     *end = 0;
    890                     c = strzcmp16(convBuffer, end-convBuffer, str, strLen);
    891                 } else {
    892                     c = -1;
    893                 }
    894                 if (kDebugStringPoolNoisy) {
    895                     ALOGI("Looking at %s, cmp=%d, l/mid/h=%d/%d/%d\n",
    896                             (const char*)s, c, (int)l, (int)mid, (int)h);
    897                 }
    898                 if (c == 0) {
    899                     if (kDebugStringPoolNoisy) {
    900                         ALOGI("MATCH!");
    901                     }
    902                     free(convBuffer);
    903                     return mid;
    904                 } else if (c < 0) {
    905                     l = mid + 1;
    906                 } else {
    907                     h = mid - 1;
    908                 }
    909             }
    910             free(convBuffer);
    911         } else {
    912             // It is unusual to get the ID from an unsorted string block...
    913             // most often this happens because we want to get IDs for style
    914             // span tags; since those always appear at the end of the string
    915             // block, start searching at the back.
    916             String8 str8(str, strLen);
    917             const size_t str8Len = str8.size();
    918             for (int i=mHeader->stringCount-1; i>=0; i--) {
    919                 const char* s = string8At(i, &len);
    920                 if (kDebugStringPoolNoisy) {
    921                     ALOGI("Looking at %s, i=%d\n", String8(s).string(), i);
    922                 }
    923                 if (s && str8Len == len && memcmp(s, str8.string(), str8Len) == 0) {
    924                     if (kDebugStringPoolNoisy) {
    925                         ALOGI("MATCH!");
    926                     }
    927                     return i;
    928                 }
    929             }
    930         }
    931 
    932     } else {
    933         if (kDebugStringPoolNoisy) {
    934             ALOGI("indexOfString UTF-16: %s", String8(str, strLen).string());
    935         }
    936 
    937         if (mHeader->flags&ResStringPool_header::SORTED_FLAG) {
    938             // Do a binary search for the string...
    939             ssize_t l = 0;
    940             ssize_t h = mHeader->stringCount-1;
    941 
    942             ssize_t mid;
    943             while (l <= h) {
    944                 mid = l + (h - l)/2;
    945                 const char16_t* s = stringAt(mid, &len);
    946                 int c = s ? strzcmp16(s, len, str, strLen) : -1;
    947                 if (kDebugStringPoolNoisy) {
    948                     ALOGI("Looking at %s, cmp=%d, l/mid/h=%d/%d/%d\n",
    949                             String8(s).string(), c, (int)l, (int)mid, (int)h);
    950                 }
    951                 if (c == 0) {
    952                     if (kDebugStringPoolNoisy) {
    953                         ALOGI("MATCH!");
    954                     }
    955                     return mid;
    956                 } else if (c < 0) {
    957                     l = mid + 1;
    958                 } else {
    959                     h = mid - 1;
    960                 }
    961             }
    962         } else {
    963             // It is unusual to get the ID from an unsorted string block...
    964             // most often this happens because we want to get IDs for style
    965             // span tags; since those always appear at the end of the string
    966             // block, start searching at the back.
    967             for (int i=mHeader->stringCount-1; i>=0; i--) {
    968                 const char16_t* s = stringAt(i, &len);
    969                 if (kDebugStringPoolNoisy) {
    970                     ALOGI("Looking at %s, i=%d\n", String8(s).string(), i);
    971                 }
    972                 if (s && strLen == len && strzcmp16(s, len, str, strLen) == 0) {
    973                     if (kDebugStringPoolNoisy) {
    974                         ALOGI("MATCH!");
    975                     }
    976                     return i;
    977                 }
    978             }
    979         }
    980     }
    981 
    982     return NAME_NOT_FOUND;
    983 }
    984 
    985 size_t ResStringPool::size() const
    986 {
    987     return (mError == NO_ERROR) ? mHeader->stringCount : 0;
    988 }
    989 
    990 size_t ResStringPool::styleCount() const
    991 {
    992     return (mError == NO_ERROR) ? mHeader->styleCount : 0;
    993 }
    994 
    995 size_t ResStringPool::bytes() const
    996 {
    997     return (mError == NO_ERROR) ? mHeader->header.size : 0;
    998 }
    999 
   1000 bool ResStringPool::isSorted() const
   1001 {
   1002     return (mHeader->flags&ResStringPool_header::SORTED_FLAG)!=0;
   1003 }
   1004 
   1005 bool ResStringPool::isUTF8() const
   1006 {
   1007     return (mHeader->flags&ResStringPool_header::UTF8_FLAG)!=0;
   1008 }
   1009 
   1010 // --------------------------------------------------------------------
   1011 // --------------------------------------------------------------------
   1012 // --------------------------------------------------------------------
   1013 
   1014 ResXMLParser::ResXMLParser(const ResXMLTree& tree)
   1015     : mTree(tree), mEventCode(BAD_DOCUMENT)
   1016 {
   1017 }
   1018 
   1019 void ResXMLParser::restart()
   1020 {
   1021     mCurNode = NULL;
   1022     mEventCode = mTree.mError == NO_ERROR ? START_DOCUMENT : BAD_DOCUMENT;
   1023 }
   1024 const ResStringPool& ResXMLParser::getStrings() const
   1025 {
   1026     return mTree.mStrings;
   1027 }
   1028 
   1029 ResXMLParser::event_code_t ResXMLParser::getEventType() const
   1030 {
   1031     return mEventCode;
   1032 }
   1033 
   1034 ResXMLParser::event_code_t ResXMLParser::next()
   1035 {
   1036     if (mEventCode == START_DOCUMENT) {
   1037         mCurNode = mTree.mRootNode;
   1038         mCurExt = mTree.mRootExt;
   1039         return (mEventCode=mTree.mRootCode);
   1040     } else if (mEventCode >= FIRST_CHUNK_CODE) {
   1041         return nextNode();
   1042     }
   1043     return mEventCode;
   1044 }
   1045 
   1046 int32_t ResXMLParser::getCommentID() const
   1047 {
   1048     return mCurNode != NULL ? dtohl(mCurNode->comment.index) : -1;
   1049 }
   1050 
   1051 const char16_t* ResXMLParser::getComment(size_t* outLen) const
   1052 {
   1053     int32_t id = getCommentID();
   1054     return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
   1055 }
   1056 
   1057 uint32_t ResXMLParser::getLineNumber() const
   1058 {
   1059     return mCurNode != NULL ? dtohl(mCurNode->lineNumber) : -1;
   1060 }
   1061 
   1062 int32_t ResXMLParser::getTextID() const
   1063 {
   1064     if (mEventCode == TEXT) {
   1065         return dtohl(((const ResXMLTree_cdataExt*)mCurExt)->data.index);
   1066     }
   1067     return -1;
   1068 }
   1069 
   1070 const char16_t* ResXMLParser::getText(size_t* outLen) const
   1071 {
   1072     int32_t id = getTextID();
   1073     return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
   1074 }
   1075 
   1076 ssize_t ResXMLParser::getTextValue(Res_value* outValue) const
   1077 {
   1078     if (mEventCode == TEXT) {
   1079         outValue->copyFrom_dtoh(((const ResXMLTree_cdataExt*)mCurExt)->typedData);
   1080         return sizeof(Res_value);
   1081     }
   1082     return BAD_TYPE;
   1083 }
   1084 
   1085 int32_t ResXMLParser::getNamespacePrefixID() const
   1086 {
   1087     if (mEventCode == START_NAMESPACE || mEventCode == END_NAMESPACE) {
   1088         return dtohl(((const ResXMLTree_namespaceExt*)mCurExt)->prefix.index);
   1089     }
   1090     return -1;
   1091 }
   1092 
   1093 const char16_t* ResXMLParser::getNamespacePrefix(size_t* outLen) const
   1094 {
   1095     int32_t id = getNamespacePrefixID();
   1096     //printf("prefix=%d  event=%p\n", id, mEventCode);
   1097     return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
   1098 }
   1099 
   1100 int32_t ResXMLParser::getNamespaceUriID() const
   1101 {
   1102     if (mEventCode == START_NAMESPACE || mEventCode == END_NAMESPACE) {
   1103         return dtohl(((const ResXMLTree_namespaceExt*)mCurExt)->uri.index);
   1104     }
   1105     return -1;
   1106 }
   1107 
   1108 const char16_t* ResXMLParser::getNamespaceUri(size_t* outLen) const
   1109 {
   1110     int32_t id = getNamespaceUriID();
   1111     //printf("uri=%d  event=%p\n", id, mEventCode);
   1112     return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
   1113 }
   1114 
   1115 int32_t ResXMLParser::getElementNamespaceID() const
   1116 {
   1117     if (mEventCode == START_TAG) {
   1118         return dtohl(((const ResXMLTree_attrExt*)mCurExt)->ns.index);
   1119     }
   1120     if (mEventCode == END_TAG) {
   1121         return dtohl(((const ResXMLTree_endElementExt*)mCurExt)->ns.index);
   1122     }
   1123     return -1;
   1124 }
   1125 
   1126 const char16_t* ResXMLParser::getElementNamespace(size_t* outLen) const
   1127 {
   1128     int32_t id = getElementNamespaceID();
   1129     return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
   1130 }
   1131 
   1132 int32_t ResXMLParser::getElementNameID() const
   1133 {
   1134     if (mEventCode == START_TAG) {
   1135         return dtohl(((const ResXMLTree_attrExt*)mCurExt)->name.index);
   1136     }
   1137     if (mEventCode == END_TAG) {
   1138         return dtohl(((const ResXMLTree_endElementExt*)mCurExt)->name.index);
   1139     }
   1140     return -1;
   1141 }
   1142 
   1143 const char16_t* ResXMLParser::getElementName(size_t* outLen) const
   1144 {
   1145     int32_t id = getElementNameID();
   1146     return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
   1147 }
   1148 
   1149 size_t ResXMLParser::getAttributeCount() const
   1150 {
   1151     if (mEventCode == START_TAG) {
   1152         return dtohs(((const ResXMLTree_attrExt*)mCurExt)->attributeCount);
   1153     }
   1154     return 0;
   1155 }
   1156 
   1157 int32_t ResXMLParser::getAttributeNamespaceID(size_t idx) const
   1158 {
   1159     if (mEventCode == START_TAG) {
   1160         const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt;
   1161         if (idx < dtohs(tag->attributeCount)) {
   1162             const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*)
   1163                 (((const uint8_t*)tag)
   1164                  + dtohs(tag->attributeStart)
   1165                  + (dtohs(tag->attributeSize)*idx));
   1166             return dtohl(attr->ns.index);
   1167         }
   1168     }
   1169     return -2;
   1170 }
   1171 
   1172 const char16_t* ResXMLParser::getAttributeNamespace(size_t idx, size_t* outLen) const
   1173 {
   1174     int32_t id = getAttributeNamespaceID(idx);
   1175     //printf("attribute namespace=%d  idx=%d  event=%p\n", id, idx, mEventCode);
   1176     if (kDebugXMLNoisy) {
   1177         printf("getAttributeNamespace 0x%zx=0x%x\n", idx, id);
   1178     }
   1179     return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
   1180 }
   1181 
   1182 const char* ResXMLParser::getAttributeNamespace8(size_t idx, size_t* outLen) const
   1183 {
   1184     int32_t id = getAttributeNamespaceID(idx);
   1185     //printf("attribute namespace=%d  idx=%d  event=%p\n", id, idx, mEventCode);
   1186     if (kDebugXMLNoisy) {
   1187         printf("getAttributeNamespace 0x%zx=0x%x\n", idx, id);
   1188     }
   1189     return id >= 0 ? mTree.mStrings.string8At(id, outLen) : NULL;
   1190 }
   1191 
   1192 int32_t ResXMLParser::getAttributeNameID(size_t idx) const
   1193 {
   1194     if (mEventCode == START_TAG) {
   1195         const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt;
   1196         if (idx < dtohs(tag->attributeCount)) {
   1197             const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*)
   1198                 (((const uint8_t*)tag)
   1199                  + dtohs(tag->attributeStart)
   1200                  + (dtohs(tag->attributeSize)*idx));
   1201             return dtohl(attr->name.index);
   1202         }
   1203     }
   1204     return -1;
   1205 }
   1206 
   1207 const char16_t* ResXMLParser::getAttributeName(size_t idx, size_t* outLen) const
   1208 {
   1209     int32_t id = getAttributeNameID(idx);
   1210     //printf("attribute name=%d  idx=%d  event=%p\n", id, idx, mEventCode);
   1211     if (kDebugXMLNoisy) {
   1212         printf("getAttributeName 0x%zx=0x%x\n", idx, id);
   1213     }
   1214     return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
   1215 }
   1216 
   1217 const char* ResXMLParser::getAttributeName8(size_t idx, size_t* outLen) const
   1218 {
   1219     int32_t id = getAttributeNameID(idx);
   1220     //printf("attribute name=%d  idx=%d  event=%p\n", id, idx, mEventCode);
   1221     if (kDebugXMLNoisy) {
   1222         printf("getAttributeName 0x%zx=0x%x\n", idx, id);
   1223     }
   1224     return id >= 0 ? mTree.mStrings.string8At(id, outLen) : NULL;
   1225 }
   1226 
   1227 uint32_t ResXMLParser::getAttributeNameResID(size_t idx) const
   1228 {
   1229     int32_t id = getAttributeNameID(idx);
   1230     if (id >= 0 && (size_t)id < mTree.mNumResIds) {
   1231         uint32_t resId = dtohl(mTree.mResIds[id]);
   1232         if (mTree.mDynamicRefTable != NULL) {
   1233             mTree.mDynamicRefTable->lookupResourceId(&resId);
   1234         }
   1235         return resId;
   1236     }
   1237     return 0;
   1238 }
   1239 
   1240 int32_t ResXMLParser::getAttributeValueStringID(size_t idx) const
   1241 {
   1242     if (mEventCode == START_TAG) {
   1243         const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt;
   1244         if (idx < dtohs(tag->attributeCount)) {
   1245             const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*)
   1246                 (((const uint8_t*)tag)
   1247                  + dtohs(tag->attributeStart)
   1248                  + (dtohs(tag->attributeSize)*idx));
   1249             return dtohl(attr->rawValue.index);
   1250         }
   1251     }
   1252     return -1;
   1253 }
   1254 
   1255 const char16_t* ResXMLParser::getAttributeStringValue(size_t idx, size_t* outLen) const
   1256 {
   1257     int32_t id = getAttributeValueStringID(idx);
   1258     if (kDebugXMLNoisy) {
   1259         printf("getAttributeValue 0x%zx=0x%x\n", idx, id);
   1260     }
   1261     return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
   1262 }
   1263 
   1264 int32_t ResXMLParser::getAttributeDataType(size_t idx) const
   1265 {
   1266     if (mEventCode == START_TAG) {
   1267         const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt;
   1268         if (idx < dtohs(tag->attributeCount)) {
   1269             const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*)
   1270                 (((const uint8_t*)tag)
   1271                  + dtohs(tag->attributeStart)
   1272                  + (dtohs(tag->attributeSize)*idx));
   1273             uint8_t type = attr->typedValue.dataType;
   1274             if (type != Res_value::TYPE_DYNAMIC_REFERENCE) {
   1275                 return type;
   1276             }
   1277 
   1278             // This is a dynamic reference. We adjust those references
   1279             // to regular references at this level, so lie to the caller.
   1280             return Res_value::TYPE_REFERENCE;
   1281         }
   1282     }
   1283     return Res_value::TYPE_NULL;
   1284 }
   1285 
   1286 int32_t ResXMLParser::getAttributeData(size_t idx) const
   1287 {
   1288     if (mEventCode == START_TAG) {
   1289         const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt;
   1290         if (idx < dtohs(tag->attributeCount)) {
   1291             const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*)
   1292                 (((const uint8_t*)tag)
   1293                  + dtohs(tag->attributeStart)
   1294                  + (dtohs(tag->attributeSize)*idx));
   1295             if (attr->typedValue.dataType != Res_value::TYPE_DYNAMIC_REFERENCE ||
   1296                     mTree.mDynamicRefTable == NULL) {
   1297                 return dtohl(attr->typedValue.data);
   1298             }
   1299 
   1300             uint32_t data = dtohl(attr->typedValue.data);
   1301             if (mTree.mDynamicRefTable->lookupResourceId(&data) == NO_ERROR) {
   1302                 return data;
   1303             }
   1304         }
   1305     }
   1306     return 0;
   1307 }
   1308 
   1309 ssize_t ResXMLParser::getAttributeValue(size_t idx, Res_value* outValue) const
   1310 {
   1311     if (mEventCode == START_TAG) {
   1312         const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt;
   1313         if (idx < dtohs(tag->attributeCount)) {
   1314             const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*)
   1315                 (((const uint8_t*)tag)
   1316                  + dtohs(tag->attributeStart)
   1317                  + (dtohs(tag->attributeSize)*idx));
   1318             outValue->copyFrom_dtoh(attr->typedValue);
   1319             if (mTree.mDynamicRefTable != NULL &&
   1320                     mTree.mDynamicRefTable->lookupResourceValue(outValue) != NO_ERROR) {
   1321                 return BAD_TYPE;
   1322             }
   1323             return sizeof(Res_value);
   1324         }
   1325     }
   1326     return BAD_TYPE;
   1327 }
   1328 
   1329 ssize_t ResXMLParser::indexOfAttribute(const char* ns, const char* attr) const
   1330 {
   1331     String16 nsStr(ns != NULL ? ns : "");
   1332     String16 attrStr(attr);
   1333     return indexOfAttribute(ns ? nsStr.string() : NULL, ns ? nsStr.size() : 0,
   1334                             attrStr.string(), attrStr.size());
   1335 }
   1336 
   1337 ssize_t ResXMLParser::indexOfAttribute(const char16_t* ns, size_t nsLen,
   1338                                        const char16_t* attr, size_t attrLen) const
   1339 {
   1340     if (mEventCode == START_TAG) {
   1341         if (attr == NULL) {
   1342             return NAME_NOT_FOUND;
   1343         }
   1344         const size_t N = getAttributeCount();
   1345         if (mTree.mStrings.isUTF8()) {
   1346             String8 ns8, attr8;
   1347             if (ns != NULL) {
   1348                 ns8 = String8(ns, nsLen);
   1349             }
   1350             attr8 = String8(attr, attrLen);
   1351             if (kDebugStringPoolNoisy) {
   1352                 ALOGI("indexOfAttribute UTF8 %s (%zu) / %s (%zu)", ns8.string(), nsLen,
   1353                         attr8.string(), attrLen);
   1354             }
   1355             for (size_t i=0; i<N; i++) {
   1356                 size_t curNsLen = 0, curAttrLen = 0;
   1357                 const char* curNs = getAttributeNamespace8(i, &curNsLen);
   1358                 const char* curAttr = getAttributeName8(i, &curAttrLen);
   1359                 if (kDebugStringPoolNoisy) {
   1360                     ALOGI("  curNs=%s (%zu), curAttr=%s (%zu)", curNs, curNsLen, curAttr, curAttrLen);
   1361                 }
   1362                 if (curAttr != NULL && curNsLen == nsLen && curAttrLen == attrLen
   1363                         && memcmp(attr8.string(), curAttr, attrLen) == 0) {
   1364                     if (ns == NULL) {
   1365                         if (curNs == NULL) {
   1366                             if (kDebugStringPoolNoisy) {
   1367                                 ALOGI("  FOUND!");
   1368                             }
   1369                             return i;
   1370                         }
   1371                     } else if (curNs != NULL) {
   1372                         //printf(" --> ns=%s, curNs=%s\n",
   1373                         //       String8(ns).string(), String8(curNs).string());
   1374                         if (memcmp(ns8.string(), curNs, nsLen) == 0) {
   1375                             if (kDebugStringPoolNoisy) {
   1376                                 ALOGI("  FOUND!");
   1377                             }
   1378                             return i;
   1379                         }
   1380                     }
   1381                 }
   1382             }
   1383         } else {
   1384             if (kDebugStringPoolNoisy) {
   1385                 ALOGI("indexOfAttribute UTF16 %s (%zu) / %s (%zu)",
   1386                         String8(ns, nsLen).string(), nsLen,
   1387                         String8(attr, attrLen).string(), attrLen);
   1388             }
   1389             for (size_t i=0; i<N; i++) {
   1390                 size_t curNsLen = 0, curAttrLen = 0;
   1391                 const char16_t* curNs = getAttributeNamespace(i, &curNsLen);
   1392                 const char16_t* curAttr = getAttributeName(i, &curAttrLen);
   1393                 if (kDebugStringPoolNoisy) {
   1394                     ALOGI("  curNs=%s (%zu), curAttr=%s (%zu)",
   1395                             String8(curNs, curNsLen).string(), curNsLen,
   1396                             String8(curAttr, curAttrLen).string(), curAttrLen);
   1397                 }
   1398                 if (curAttr != NULL && curNsLen == nsLen && curAttrLen == attrLen
   1399                         && (memcmp(attr, curAttr, attrLen*sizeof(char16_t)) == 0)) {
   1400                     if (ns == NULL) {
   1401                         if (curNs == NULL) {
   1402                             if (kDebugStringPoolNoisy) {
   1403                                 ALOGI("  FOUND!");
   1404                             }
   1405                             return i;
   1406                         }
   1407                     } else if (curNs != NULL) {
   1408                         //printf(" --> ns=%s, curNs=%s\n",
   1409                         //       String8(ns).string(), String8(curNs).string());
   1410                         if (memcmp(ns, curNs, nsLen*sizeof(char16_t)) == 0) {
   1411                             if (kDebugStringPoolNoisy) {
   1412                                 ALOGI("  FOUND!");
   1413                             }
   1414                             return i;
   1415                         }
   1416                     }
   1417                 }
   1418             }
   1419         }
   1420     }
   1421 
   1422     return NAME_NOT_FOUND;
   1423 }
   1424 
   1425 ssize_t ResXMLParser::indexOfID() const
   1426 {
   1427     if (mEventCode == START_TAG) {
   1428         const ssize_t idx = dtohs(((const ResXMLTree_attrExt*)mCurExt)->idIndex);
   1429         if (idx > 0) return (idx-1);
   1430     }
   1431     return NAME_NOT_FOUND;
   1432 }
   1433 
   1434 ssize_t ResXMLParser::indexOfClass() const
   1435 {
   1436     if (mEventCode == START_TAG) {
   1437         const ssize_t idx = dtohs(((const ResXMLTree_attrExt*)mCurExt)->classIndex);
   1438         if (idx > 0) return (idx-1);
   1439     }
   1440     return NAME_NOT_FOUND;
   1441 }
   1442 
   1443 ssize_t ResXMLParser::indexOfStyle() const
   1444 {
   1445     if (mEventCode == START_TAG) {
   1446         const ssize_t idx = dtohs(((const ResXMLTree_attrExt*)mCurExt)->styleIndex);
   1447         if (idx > 0) return (idx-1);
   1448     }
   1449     return NAME_NOT_FOUND;
   1450 }
   1451 
   1452 ResXMLParser::event_code_t ResXMLParser::nextNode()
   1453 {
   1454     if (mEventCode < 0) {
   1455         return mEventCode;
   1456     }
   1457 
   1458     do {
   1459         const ResXMLTree_node* next = (const ResXMLTree_node*)
   1460             (((const uint8_t*)mCurNode) + dtohl(mCurNode->header.size));
   1461         if (kDebugXMLNoisy) {
   1462             ALOGI("Next node: prev=%p, next=%p\n", mCurNode, next);
   1463         }
   1464 
   1465         if (((const uint8_t*)next) >= mTree.mDataEnd) {
   1466             mCurNode = NULL;
   1467             return (mEventCode=END_DOCUMENT);
   1468         }
   1469 
   1470         if (mTree.validateNode(next) != NO_ERROR) {
   1471             mCurNode = NULL;
   1472             return (mEventCode=BAD_DOCUMENT);
   1473         }
   1474 
   1475         mCurNode = next;
   1476         const uint16_t headerSize = dtohs(next->header.headerSize);
   1477         const uint32_t totalSize = dtohl(next->header.size);
   1478         mCurExt = ((const uint8_t*)next) + headerSize;
   1479         size_t minExtSize = 0;
   1480         event_code_t eventCode = (event_code_t)dtohs(next->header.type);
   1481         switch ((mEventCode=eventCode)) {
   1482             case RES_XML_START_NAMESPACE_TYPE:
   1483             case RES_XML_END_NAMESPACE_TYPE:
   1484                 minExtSize = sizeof(ResXMLTree_namespaceExt);
   1485                 break;
   1486             case RES_XML_START_ELEMENT_TYPE:
   1487                 minExtSize = sizeof(ResXMLTree_attrExt);
   1488                 break;
   1489             case RES_XML_END_ELEMENT_TYPE:
   1490                 minExtSize = sizeof(ResXMLTree_endElementExt);
   1491                 break;
   1492             case RES_XML_CDATA_TYPE:
   1493                 minExtSize = sizeof(ResXMLTree_cdataExt);
   1494                 break;
   1495             default:
   1496                 ALOGW("Unknown XML block: header type %d in node at %d\n",
   1497                      (int)dtohs(next->header.type),
   1498                      (int)(((const uint8_t*)next)-((const uint8_t*)mTree.mHeader)));
   1499                 continue;
   1500         }
   1501 
   1502         if ((totalSize-headerSize) < minExtSize) {
   1503             ALOGW("Bad XML block: header type 0x%x in node at 0x%x has size %d, need %d\n",
   1504                  (int)dtohs(next->header.type),
   1505                  (int)(((const uint8_t*)next)-((const uint8_t*)mTree.mHeader)),
   1506                  (int)(totalSize-headerSize), (int)minExtSize);
   1507             return (mEventCode=BAD_DOCUMENT);
   1508         }
   1509 
   1510         //printf("CurNode=%p, CurExt=%p, headerSize=%d, minExtSize=%d\n",
   1511         //       mCurNode, mCurExt, headerSize, minExtSize);
   1512 
   1513         return eventCode;
   1514     } while (true);
   1515 }
   1516 
   1517 void ResXMLParser::getPosition(ResXMLParser::ResXMLPosition* pos) const
   1518 {
   1519     pos->eventCode = mEventCode;
   1520     pos->curNode = mCurNode;
   1521     pos->curExt = mCurExt;
   1522 }
   1523 
   1524 void ResXMLParser::setPosition(const ResXMLParser::ResXMLPosition& pos)
   1525 {
   1526     mEventCode = pos.eventCode;
   1527     mCurNode = pos.curNode;
   1528     mCurExt = pos.curExt;
   1529 }
   1530 
   1531 // --------------------------------------------------------------------
   1532 
   1533 static volatile int32_t gCount = 0;
   1534 
   1535 ResXMLTree::ResXMLTree(const DynamicRefTable* dynamicRefTable)
   1536     : ResXMLParser(*this)
   1537     , mDynamicRefTable(dynamicRefTable)
   1538     , mError(NO_INIT), mOwnedData(NULL)
   1539 {
   1540     if (kDebugResXMLTree) {
   1541         ALOGI("Creating ResXMLTree %p #%d\n", this, android_atomic_inc(&gCount)+1);
   1542     }
   1543     restart();
   1544 }
   1545 
   1546 ResXMLTree::ResXMLTree()
   1547     : ResXMLParser(*this)
   1548     , mDynamicRefTable(NULL)
   1549     , mError(NO_INIT), mOwnedData(NULL)
   1550 {
   1551     if (kDebugResXMLTree) {
   1552         ALOGI("Creating ResXMLTree %p #%d\n", this, android_atomic_inc(&gCount)+1);
   1553     }
   1554     restart();
   1555 }
   1556 
   1557 ResXMLTree::~ResXMLTree()
   1558 {
   1559     if (kDebugResXMLTree) {
   1560         ALOGI("Destroying ResXMLTree in %p #%d\n", this, android_atomic_dec(&gCount)-1);
   1561     }
   1562     uninit();
   1563 }
   1564 
   1565 status_t ResXMLTree::setTo(const void* data, size_t size, bool copyData)
   1566 {
   1567     uninit();
   1568     mEventCode = START_DOCUMENT;
   1569 
   1570     if (!data || !size) {
   1571         return (mError=BAD_TYPE);
   1572     }
   1573 
   1574     if (copyData) {
   1575         mOwnedData = malloc(size);
   1576         if (mOwnedData == NULL) {
   1577             return (mError=NO_MEMORY);
   1578         }
   1579         memcpy(mOwnedData, data, size);
   1580         data = mOwnedData;
   1581     }
   1582 
   1583     mHeader = (const ResXMLTree_header*)data;
   1584     mSize = dtohl(mHeader->header.size);
   1585     if (dtohs(mHeader->header.headerSize) > mSize || mSize > size) {
   1586         ALOGW("Bad XML block: header size %d or total size %d is larger than data size %d\n",
   1587              (int)dtohs(mHeader->header.headerSize),
   1588              (int)dtohl(mHeader->header.size), (int)size);
   1589         mError = BAD_TYPE;
   1590         restart();
   1591         return mError;
   1592     }
   1593     mDataEnd = ((const uint8_t*)mHeader) + mSize;
   1594 
   1595     mStrings.uninit();
   1596     mRootNode = NULL;
   1597     mResIds = NULL;
   1598     mNumResIds = 0;
   1599 
   1600     // First look for a couple interesting chunks: the string block
   1601     // and first XML node.
   1602     const ResChunk_header* chunk =
   1603         (const ResChunk_header*)(((const uint8_t*)mHeader) + dtohs(mHeader->header.headerSize));
   1604     const ResChunk_header* lastChunk = chunk;
   1605     while (((const uint8_t*)chunk) < (mDataEnd-sizeof(ResChunk_header)) &&
   1606            ((const uint8_t*)chunk) < (mDataEnd-dtohl(chunk->size))) {
   1607         status_t err = validate_chunk(chunk, sizeof(ResChunk_header), mDataEnd, "XML");
   1608         if (err != NO_ERROR) {
   1609             mError = err;
   1610             goto done;
   1611         }
   1612         const uint16_t type = dtohs(chunk->type);
   1613         const size_t size = dtohl(chunk->size);
   1614         if (kDebugXMLNoisy) {
   1615             printf("Scanning @ %p: type=0x%x, size=0x%zx\n",
   1616                     (void*)(((uintptr_t)chunk)-((uintptr_t)mHeader)), type, size);
   1617         }
   1618         if (type == RES_STRING_POOL_TYPE) {
   1619             mStrings.setTo(chunk, size);
   1620         } else if (type == RES_XML_RESOURCE_MAP_TYPE) {
   1621             mResIds = (const uint32_t*)
   1622                 (((const uint8_t*)chunk)+dtohs(chunk->headerSize));
   1623             mNumResIds = (dtohl(chunk->size)-dtohs(chunk->headerSize))/sizeof(uint32_t);
   1624         } else if (type >= RES_XML_FIRST_CHUNK_TYPE
   1625                    && type <= RES_XML_LAST_CHUNK_TYPE) {
   1626             if (validateNode((const ResXMLTree_node*)chunk) != NO_ERROR) {
   1627                 mError = BAD_TYPE;
   1628                 goto done;
   1629             }
   1630             mCurNode = (const ResXMLTree_node*)lastChunk;
   1631             if (nextNode() == BAD_DOCUMENT) {
   1632                 mError = BAD_TYPE;
   1633                 goto done;
   1634             }
   1635             mRootNode = mCurNode;
   1636             mRootExt = mCurExt;
   1637             mRootCode = mEventCode;
   1638             break;
   1639         } else {
   1640             if (kDebugXMLNoisy) {
   1641                 printf("Skipping unknown chunk!\n");
   1642             }
   1643         }
   1644         lastChunk = chunk;
   1645         chunk = (const ResChunk_header*)
   1646             (((const uint8_t*)chunk) + size);
   1647     }
   1648 
   1649     if (mRootNode == NULL) {
   1650         ALOGW("Bad XML block: no root element node found\n");
   1651         mError = BAD_TYPE;
   1652         goto done;
   1653     }
   1654 
   1655     mError = mStrings.getError();
   1656 
   1657 done:
   1658     restart();
   1659     return mError;
   1660 }
   1661 
   1662 status_t ResXMLTree::getError() const
   1663 {
   1664     return mError;
   1665 }
   1666 
   1667 void ResXMLTree::uninit()
   1668 {
   1669     mError = NO_INIT;
   1670     mStrings.uninit();
   1671     if (mOwnedData) {
   1672         free(mOwnedData);
   1673         mOwnedData = NULL;
   1674     }
   1675     restart();
   1676 }
   1677 
   1678 status_t ResXMLTree::validateNode(const ResXMLTree_node* node) const
   1679 {
   1680     const uint16_t eventCode = dtohs(node->header.type);
   1681 
   1682     status_t err = validate_chunk(
   1683         &node->header, sizeof(ResXMLTree_node),
   1684         mDataEnd, "ResXMLTree_node");
   1685 
   1686     if (err >= NO_ERROR) {
   1687         // Only perform additional validation on START nodes
   1688         if (eventCode != RES_XML_START_ELEMENT_TYPE) {
   1689             return NO_ERROR;
   1690         }
   1691 
   1692         const uint16_t headerSize = dtohs(node->header.headerSize);
   1693         const uint32_t size = dtohl(node->header.size);
   1694         const ResXMLTree_attrExt* attrExt = (const ResXMLTree_attrExt*)
   1695             (((const uint8_t*)node) + headerSize);
   1696         // check for sensical values pulled out of the stream so far...
   1697         if ((size >= headerSize + sizeof(ResXMLTree_attrExt))
   1698                 && ((void*)attrExt > (void*)node)) {
   1699             const size_t attrSize = ((size_t)dtohs(attrExt->attributeSize))
   1700                 * dtohs(attrExt->attributeCount);
   1701             if ((dtohs(attrExt->attributeStart)+attrSize) <= (size-headerSize)) {
   1702                 return NO_ERROR;
   1703             }
   1704             ALOGW("Bad XML block: node attributes use 0x%x bytes, only have 0x%x bytes\n",
   1705                     (unsigned int)(dtohs(attrExt->attributeStart)+attrSize),
   1706                     (unsigned int)(size-headerSize));
   1707         }
   1708         else {
   1709             ALOGW("Bad XML start block: node header size 0x%x, size 0x%x\n",
   1710                 (unsigned int)headerSize, (unsigned int)size);
   1711         }
   1712         return BAD_TYPE;
   1713     }
   1714 
   1715     return err;
   1716 
   1717 #if 0
   1718     const bool isStart = dtohs(node->header.type) == RES_XML_START_ELEMENT_TYPE;
   1719 
   1720     const uint16_t headerSize = dtohs(node->header.headerSize);
   1721     const uint32_t size = dtohl(node->header.size);
   1722 
   1723     if (headerSize >= (isStart ? sizeof(ResXMLTree_attrNode) : sizeof(ResXMLTree_node))) {
   1724         if (size >= headerSize) {
   1725             if (((const uint8_t*)node) <= (mDataEnd-size)) {
   1726                 if (!isStart) {
   1727                     return NO_ERROR;
   1728                 }
   1729                 if ((((size_t)dtohs(node->attributeSize))*dtohs(node->attributeCount))
   1730                         <= (size-headerSize)) {
   1731                     return NO_ERROR;
   1732                 }
   1733                 ALOGW("Bad XML block: node attributes use 0x%x bytes, only have 0x%x bytes\n",
   1734                         ((int)dtohs(node->attributeSize))*dtohs(node->attributeCount),
   1735                         (int)(size-headerSize));
   1736                 return BAD_TYPE;
   1737             }
   1738             ALOGW("Bad XML block: node at 0x%x extends beyond data end 0x%x\n",
   1739                     (int)(((const uint8_t*)node)-((const uint8_t*)mHeader)), (int)mSize);
   1740             return BAD_TYPE;
   1741         }
   1742         ALOGW("Bad XML block: node at 0x%x header size 0x%x smaller than total size 0x%x\n",
   1743                 (int)(((const uint8_t*)node)-((const uint8_t*)mHeader)),
   1744                 (int)headerSize, (int)size);
   1745         return BAD_TYPE;
   1746     }
   1747     ALOGW("Bad XML block: node at 0x%x header size 0x%x too small\n",
   1748             (int)(((const uint8_t*)node)-((const uint8_t*)mHeader)),
   1749             (int)headerSize);
   1750     return BAD_TYPE;
   1751 #endif
   1752 }
   1753 
   1754 // --------------------------------------------------------------------
   1755 // --------------------------------------------------------------------
   1756 // --------------------------------------------------------------------
   1757 
   1758 void ResTable_config::copyFromDeviceNoSwap(const ResTable_config& o) {
   1759     const size_t size = dtohl(o.size);
   1760     if (size >= sizeof(ResTable_config)) {
   1761         *this = o;
   1762     } else {
   1763         memcpy(this, &o, size);
   1764         memset(((uint8_t*)this)+size, 0, sizeof(ResTable_config)-size);
   1765     }
   1766 }
   1767 
   1768 /* static */ size_t unpackLanguageOrRegion(const char in[2], const char base,
   1769         char out[4]) {
   1770   if (in[0] & 0x80) {
   1771       // The high bit is "1", which means this is a packed three letter
   1772       // language code.
   1773 
   1774       // The smallest 5 bits of the second char are the first alphabet.
   1775       const uint8_t first = in[1] & 0x1f;
   1776       // The last three bits of the second char and the first two bits
   1777       // of the first char are the second alphabet.
   1778       const uint8_t second = ((in[1] & 0xe0) >> 5) + ((in[0] & 0x03) << 3);
   1779       // Bits 3 to 7 (inclusive) of the first char are the third alphabet.
   1780       const uint8_t third = (in[0] & 0x7c) >> 2;
   1781 
   1782       out[0] = first + base;
   1783       out[1] = second + base;
   1784       out[2] = third + base;
   1785       out[3] = 0;
   1786 
   1787       return 3;
   1788   }
   1789 
   1790   if (in[0]) {
   1791       memcpy(out, in, 2);
   1792       memset(out + 2, 0, 2);
   1793       return 2;
   1794   }
   1795 
   1796   memset(out, 0, 4);
   1797   return 0;
   1798 }
   1799 
   1800 /* static */ void packLanguageOrRegion(const char* in, const char base,
   1801         char out[2]) {
   1802   if (in[2] == 0 || in[2] == '-') {
   1803       out[0] = in[0];
   1804       out[1] = in[1];
   1805   } else {
   1806       uint8_t first = (in[0] - base) & 0x007f;
   1807       uint8_t second = (in[1] - base) & 0x007f;
   1808       uint8_t third = (in[2] - base) & 0x007f;
   1809 
   1810       out[0] = (0x80 | (third << 2) | (second >> 3));
   1811       out[1] = ((second << 5) | first);
   1812   }
   1813 }
   1814 
   1815 
   1816 void ResTable_config::packLanguage(const char* language) {
   1817     packLanguageOrRegion(language, 'a', this->language);
   1818 }
   1819 
   1820 void ResTable_config::packRegion(const char* region) {
   1821     packLanguageOrRegion(region, '0', this->country);
   1822 }
   1823 
   1824 size_t ResTable_config::unpackLanguage(char language[4]) const {
   1825     return unpackLanguageOrRegion(this->language, 'a', language);
   1826 }
   1827 
   1828 size_t ResTable_config::unpackRegion(char region[4]) const {
   1829     return unpackLanguageOrRegion(this->country, '0', region);
   1830 }
   1831 
   1832 
   1833 void ResTable_config::copyFromDtoH(const ResTable_config& o) {
   1834     copyFromDeviceNoSwap(o);
   1835     size = sizeof(ResTable_config);
   1836     mcc = dtohs(mcc);
   1837     mnc = dtohs(mnc);
   1838     density = dtohs(density);
   1839     screenWidth = dtohs(screenWidth);
   1840     screenHeight = dtohs(screenHeight);
   1841     sdkVersion = dtohs(sdkVersion);
   1842     minorVersion = dtohs(minorVersion);
   1843     smallestScreenWidthDp = dtohs(smallestScreenWidthDp);
   1844     screenWidthDp = dtohs(screenWidthDp);
   1845     screenHeightDp = dtohs(screenHeightDp);
   1846 }
   1847 
   1848 void ResTable_config::swapHtoD() {
   1849     size = htodl(size);
   1850     mcc = htods(mcc);
   1851     mnc = htods(mnc);
   1852     density = htods(density);
   1853     screenWidth = htods(screenWidth);
   1854     screenHeight = htods(screenHeight);
   1855     sdkVersion = htods(sdkVersion);
   1856     minorVersion = htods(minorVersion);
   1857     smallestScreenWidthDp = htods(smallestScreenWidthDp);
   1858     screenWidthDp = htods(screenWidthDp);
   1859     screenHeightDp = htods(screenHeightDp);
   1860 }
   1861 
   1862 /* static */ inline int compareLocales(const ResTable_config &l, const ResTable_config &r) {
   1863     if (l.locale != r.locale) {
   1864         // NOTE: This is the old behaviour with respect to comparison orders.
   1865         // The diff value here doesn't make much sense (given our bit packing scheme)
   1866         // but it's stable, and that's all we need.
   1867         return l.locale - r.locale;
   1868     }
   1869 
   1870     // The language & region are equal, so compare the scripts and variants.
   1871     int script = memcmp(l.localeScript, r.localeScript, sizeof(l.localeScript));
   1872     if (script) {
   1873         return script;
   1874     }
   1875 
   1876     // The language, region and script are equal, so compare variants.
   1877     //
   1878     // This should happen very infrequently (if at all.)
   1879     return memcmp(l.localeVariant, r.localeVariant, sizeof(l.localeVariant));
   1880 }
   1881 
   1882 int ResTable_config::compare(const ResTable_config& o) const {
   1883     int32_t diff = (int32_t)(imsi - o.imsi);
   1884     if (diff != 0) return diff;
   1885     diff = compareLocales(*this, o);
   1886     if (diff != 0) return diff;
   1887     diff = (int32_t)(screenType - o.screenType);
   1888     if (diff != 0) return diff;
   1889     diff = (int32_t)(input - o.input);
   1890     if (diff != 0) return diff;
   1891     diff = (int32_t)(screenSize - o.screenSize);
   1892     if (diff != 0) return diff;
   1893     diff = (int32_t)(version - o.version);
   1894     if (diff != 0) return diff;
   1895     diff = (int32_t)(screenLayout - o.screenLayout);
   1896     if (diff != 0) return diff;
   1897     diff = (int32_t)(screenLayout2 - o.screenLayout2);
   1898     if (diff != 0) return diff;
   1899     diff = (int32_t)(uiMode - o.uiMode);
   1900     if (diff != 0) return diff;
   1901     diff = (int32_t)(smallestScreenWidthDp - o.smallestScreenWidthDp);
   1902     if (diff != 0) return diff;
   1903     diff = (int32_t)(screenSizeDp - o.screenSizeDp);
   1904     return (int)diff;
   1905 }
   1906 
   1907 int ResTable_config::compareLogical(const ResTable_config& o) const {
   1908     if (mcc != o.mcc) {
   1909         return mcc < o.mcc ? -1 : 1;
   1910     }
   1911     if (mnc != o.mnc) {
   1912         return mnc < o.mnc ? -1 : 1;
   1913     }
   1914 
   1915     int diff = compareLocales(*this, o);
   1916     if (diff < 0) {
   1917         return -1;
   1918     }
   1919     if (diff > 0) {
   1920         return 1;
   1921     }
   1922 
   1923     if ((screenLayout & MASK_LAYOUTDIR) != (o.screenLayout & MASK_LAYOUTDIR)) {
   1924         return (screenLayout & MASK_LAYOUTDIR) < (o.screenLayout & MASK_LAYOUTDIR) ? -1 : 1;
   1925     }
   1926     if (smallestScreenWidthDp != o.smallestScreenWidthDp) {
   1927         return smallestScreenWidthDp < o.smallestScreenWidthDp ? -1 : 1;
   1928     }
   1929     if (screenWidthDp != o.screenWidthDp) {
   1930         return screenWidthDp < o.screenWidthDp ? -1 : 1;
   1931     }
   1932     if (screenHeightDp != o.screenHeightDp) {
   1933         return screenHeightDp < o.screenHeightDp ? -1 : 1;
   1934     }
   1935     if (screenWidth != o.screenWidth) {
   1936         return screenWidth < o.screenWidth ? -1 : 1;
   1937     }
   1938     if (screenHeight != o.screenHeight) {
   1939         return screenHeight < o.screenHeight ? -1 : 1;
   1940     }
   1941     if (density != o.density) {
   1942         return density < o.density ? -1 : 1;
   1943     }
   1944     if (orientation != o.orientation) {
   1945         return orientation < o.orientation ? -1 : 1;
   1946     }
   1947     if (touchscreen != o.touchscreen) {
   1948         return touchscreen < o.touchscreen ? -1 : 1;
   1949     }
   1950     if (input != o.input) {
   1951         return input < o.input ? -1 : 1;
   1952     }
   1953     if (screenLayout != o.screenLayout) {
   1954         return screenLayout < o.screenLayout ? -1 : 1;
   1955     }
   1956     if (screenLayout2 != o.screenLayout2) {
   1957         return screenLayout2 < o.screenLayout2 ? -1 : 1;
   1958     }
   1959     if (uiMode != o.uiMode) {
   1960         return uiMode < o.uiMode ? -1 : 1;
   1961     }
   1962     if (version != o.version) {
   1963         return version < o.version ? -1 : 1;
   1964     }
   1965     return 0;
   1966 }
   1967 
   1968 int ResTable_config::diff(const ResTable_config& o) const {
   1969     int diffs = 0;
   1970     if (mcc != o.mcc) diffs |= CONFIG_MCC;
   1971     if (mnc != o.mnc) diffs |= CONFIG_MNC;
   1972     if (orientation != o.orientation) diffs |= CONFIG_ORIENTATION;
   1973     if (density != o.density) diffs |= CONFIG_DENSITY;
   1974     if (touchscreen != o.touchscreen) diffs |= CONFIG_TOUCHSCREEN;
   1975     if (((inputFlags^o.inputFlags)&(MASK_KEYSHIDDEN|MASK_NAVHIDDEN)) != 0)
   1976             diffs |= CONFIG_KEYBOARD_HIDDEN;
   1977     if (keyboard != o.keyboard) diffs |= CONFIG_KEYBOARD;
   1978     if (navigation != o.navigation) diffs |= CONFIG_NAVIGATION;
   1979     if (screenSize != o.screenSize) diffs |= CONFIG_SCREEN_SIZE;
   1980     if (version != o.version) diffs |= CONFIG_VERSION;
   1981     if ((screenLayout & MASK_LAYOUTDIR) != (o.screenLayout & MASK_LAYOUTDIR)) diffs |= CONFIG_LAYOUTDIR;
   1982     if ((screenLayout & ~MASK_LAYOUTDIR) != (o.screenLayout & ~MASK_LAYOUTDIR)) diffs |= CONFIG_SCREEN_LAYOUT;
   1983     if ((screenLayout2 & MASK_SCREENROUND) != (o.screenLayout2 & MASK_SCREENROUND)) diffs |= CONFIG_SCREEN_ROUND;
   1984     if (uiMode != o.uiMode) diffs |= CONFIG_UI_MODE;
   1985     if (smallestScreenWidthDp != o.smallestScreenWidthDp) diffs |= CONFIG_SMALLEST_SCREEN_SIZE;
   1986     if (screenSizeDp != o.screenSizeDp) diffs |= CONFIG_SCREEN_SIZE;
   1987 
   1988     const int diff = compareLocales(*this, o);
   1989     if (diff) diffs |= CONFIG_LOCALE;
   1990 
   1991     return diffs;
   1992 }
   1993 
   1994 int ResTable_config::isLocaleMoreSpecificThan(const ResTable_config& o) const {
   1995     if (locale || o.locale) {
   1996         if (language[0] != o.language[0]) {
   1997             if (!language[0]) return -1;
   1998             if (!o.language[0]) return 1;
   1999         }
   2000 
   2001         if (country[0] != o.country[0]) {
   2002             if (!country[0]) return -1;
   2003             if (!o.country[0]) return 1;
   2004         }
   2005     }
   2006 
   2007     // There isn't a well specified "importance" order between variants and
   2008     // scripts. We can't easily tell whether, say "en-Latn-US" is more or less
   2009     // specific than "en-US-POSIX".
   2010     //
   2011     // We therefore arbitrarily decide to give priority to variants over
   2012     // scripts since it seems more useful to do so. We will consider
   2013     // "en-US-POSIX" to be more specific than "en-Latn-US".
   2014 
   2015     const int score = ((localeScript[0] != 0) ? 1 : 0) +
   2016         ((localeVariant[0] != 0) ? 2 : 0);
   2017 
   2018     const int oScore = ((o.localeScript[0] != 0) ? 1 : 0) +
   2019         ((o.localeVariant[0] != 0) ? 2 : 0);
   2020 
   2021     return score - oScore;
   2022 
   2023 }
   2024 
   2025 bool ResTable_config::isMoreSpecificThan(const ResTable_config& o) const {
   2026     // The order of the following tests defines the importance of one
   2027     // configuration parameter over another.  Those tests first are more
   2028     // important, trumping any values in those following them.
   2029     if (imsi || o.imsi) {
   2030         if (mcc != o.mcc) {
   2031             if (!mcc) return false;
   2032             if (!o.mcc) return true;
   2033         }
   2034 
   2035         if (mnc != o.mnc) {
   2036             if (!mnc) return false;
   2037             if (!o.mnc) return true;
   2038         }
   2039     }
   2040 
   2041     if (locale || o.locale) {
   2042         const int diff = isLocaleMoreSpecificThan(o);
   2043         if (diff < 0) {
   2044             return false;
   2045         }
   2046 
   2047         if (diff > 0) {
   2048             return true;
   2049         }
   2050     }
   2051 
   2052     if (screenLayout || o.screenLayout) {
   2053         if (((screenLayout^o.screenLayout) & MASK_LAYOUTDIR) != 0) {
   2054             if (!(screenLayout & MASK_LAYOUTDIR)) return false;
   2055             if (!(o.screenLayout & MASK_LAYOUTDIR)) return true;
   2056         }
   2057     }
   2058 
   2059     if (smallestScreenWidthDp || o.smallestScreenWidthDp) {
   2060         if (smallestScreenWidthDp != o.smallestScreenWidthDp) {
   2061             if (!smallestScreenWidthDp) return false;
   2062             if (!o.smallestScreenWidthDp) return true;
   2063         }
   2064     }
   2065 
   2066     if (screenSizeDp || o.screenSizeDp) {
   2067         if (screenWidthDp != o.screenWidthDp) {
   2068             if (!screenWidthDp) return false;
   2069             if (!o.screenWidthDp) return true;
   2070         }
   2071 
   2072         if (screenHeightDp != o.screenHeightDp) {
   2073             if (!screenHeightDp) return false;
   2074             if (!o.screenHeightDp) return true;
   2075         }
   2076     }
   2077 
   2078     if (screenLayout || o.screenLayout) {
   2079         if (((screenLayout^o.screenLayout) & MASK_SCREENSIZE) != 0) {
   2080             if (!(screenLayout & MASK_SCREENSIZE)) return false;
   2081             if (!(o.screenLayout & MASK_SCREENSIZE)) return true;
   2082         }
   2083         if (((screenLayout^o.screenLayout) & MASK_SCREENLONG) != 0) {
   2084             if (!(screenLayout & MASK_SCREENLONG)) return false;
   2085             if (!(o.screenLayout & MASK_SCREENLONG)) return true;
   2086         }
   2087     }
   2088 
   2089     if (screenLayout2 || o.screenLayout2) {
   2090         if (((screenLayout2^o.screenLayout2) & MASK_SCREENROUND) != 0) {
   2091             if (!(screenLayout2 & MASK_SCREENROUND)) return false;
   2092             if (!(o.screenLayout2 & MASK_SCREENROUND)) return true;
   2093         }
   2094     }
   2095 
   2096     if (orientation != o.orientation) {
   2097         if (!orientation) return false;
   2098         if (!o.orientation) return true;
   2099     }
   2100 
   2101     if (uiMode || o.uiMode) {
   2102         if (((uiMode^o.uiMode) & MASK_UI_MODE_TYPE) != 0) {
   2103             if (!(uiMode & MASK_UI_MODE_TYPE)) return false;
   2104             if (!(o.uiMode & MASK_UI_MODE_TYPE)) return true;
   2105         }
   2106         if (((uiMode^o.uiMode) & MASK_UI_MODE_NIGHT) != 0) {
   2107             if (!(uiMode & MASK_UI_MODE_NIGHT)) return false;
   2108             if (!(o.uiMode & MASK_UI_MODE_NIGHT)) return true;
   2109         }
   2110     }
   2111 
   2112     // density is never 'more specific'
   2113     // as the default just equals 160
   2114 
   2115     if (touchscreen != o.touchscreen) {
   2116         if (!touchscreen) return false;
   2117         if (!o.touchscreen) return true;
   2118     }
   2119 
   2120     if (input || o.input) {
   2121         if (((inputFlags^o.inputFlags) & MASK_KEYSHIDDEN) != 0) {
   2122             if (!(inputFlags & MASK_KEYSHIDDEN)) return false;
   2123             if (!(o.inputFlags & MASK_KEYSHIDDEN)) return true;
   2124         }
   2125 
   2126         if (((inputFlags^o.inputFlags) & MASK_NAVHIDDEN) != 0) {
   2127             if (!(inputFlags & MASK_NAVHIDDEN)) return false;
   2128             if (!(o.inputFlags & MASK_NAVHIDDEN)) return true;
   2129         }
   2130 
   2131         if (keyboard != o.keyboard) {
   2132             if (!keyboard) return false;
   2133             if (!o.keyboard) return true;
   2134         }
   2135 
   2136         if (navigation != o.navigation) {
   2137             if (!navigation) return false;
   2138             if (!o.navigation) return true;
   2139         }
   2140     }
   2141 
   2142     if (screenSize || o.screenSize) {
   2143         if (screenWidth != o.screenWidth) {
   2144             if (!screenWidth) return false;
   2145             if (!o.screenWidth) return true;
   2146         }
   2147 
   2148         if (screenHeight != o.screenHeight) {
   2149             if (!screenHeight) return false;
   2150             if (!o.screenHeight) return true;
   2151         }
   2152     }
   2153 
   2154     if (version || o.version) {
   2155         if (sdkVersion != o.sdkVersion) {
   2156             if (!sdkVersion) return false;
   2157             if (!o.sdkVersion) return true;
   2158         }
   2159 
   2160         if (minorVersion != o.minorVersion) {
   2161             if (!minorVersion) return false;
   2162             if (!o.minorVersion) return true;
   2163         }
   2164     }
   2165     return false;
   2166 }
   2167 
   2168 bool ResTable_config::isBetterThan(const ResTable_config& o,
   2169         const ResTable_config* requested) const {
   2170     if (requested) {
   2171         if (imsi || o.imsi) {
   2172             if ((mcc != o.mcc) && requested->mcc) {
   2173                 return (mcc);
   2174             }
   2175 
   2176             if ((mnc != o.mnc) && requested->mnc) {
   2177                 return (mnc);
   2178             }
   2179         }
   2180 
   2181         if (locale || o.locale) {
   2182             if ((language[0] != o.language[0]) && requested->language[0]) {
   2183                 return (language[0]);
   2184             }
   2185 
   2186             if ((country[0] != o.country[0]) && requested->country[0]) {
   2187                 return (country[0]);
   2188             }
   2189         }
   2190 
   2191         if (localeScript[0] || o.localeScript[0]) {
   2192             if (localeScript[0] != o.localeScript[0] && requested->localeScript[0]) {
   2193                 return localeScript[0];
   2194             }
   2195         }
   2196 
   2197         if (localeVariant[0] || o.localeVariant[0]) {
   2198             if (localeVariant[0] != o.localeVariant[0] && requested->localeVariant[0]) {
   2199                 return localeVariant[0];
   2200             }
   2201         }
   2202 
   2203         if (screenLayout || o.screenLayout) {
   2204             if (((screenLayout^o.screenLayout) & MASK_LAYOUTDIR) != 0
   2205                     && (requested->screenLayout & MASK_LAYOUTDIR)) {
   2206                 int myLayoutDir = screenLayout & MASK_LAYOUTDIR;
   2207                 int oLayoutDir = o.screenLayout & MASK_LAYOUTDIR;
   2208                 return (myLayoutDir > oLayoutDir);
   2209             }
   2210         }
   2211 
   2212         if (smallestScreenWidthDp || o.smallestScreenWidthDp) {
   2213             // The configuration closest to the actual size is best.
   2214             // We assume that larger configs have already been filtered
   2215             // out at this point.  That means we just want the largest one.
   2216             if (smallestScreenWidthDp != o.smallestScreenWidthDp) {
   2217                 return smallestScreenWidthDp > o.smallestScreenWidthDp;
   2218             }
   2219         }
   2220 
   2221         if (screenSizeDp || o.screenSizeDp) {
   2222             // "Better" is based on the sum of the difference between both
   2223             // width and height from the requested dimensions.  We are
   2224             // assuming the invalid configs (with smaller dimens) have
   2225             // already been filtered.  Note that if a particular dimension
   2226             // is unspecified, we will end up with a large value (the
   2227             // difference between 0 and the requested dimension), which is
   2228             // good since we will prefer a config that has specified a
   2229             // dimension value.
   2230             int myDelta = 0, otherDelta = 0;
   2231             if (requested->screenWidthDp) {
   2232                 myDelta += requested->screenWidthDp - screenWidthDp;
   2233                 otherDelta += requested->screenWidthDp - o.screenWidthDp;
   2234             }
   2235             if (requested->screenHeightDp) {
   2236                 myDelta += requested->screenHeightDp - screenHeightDp;
   2237                 otherDelta += requested->screenHeightDp - o.screenHeightDp;
   2238             }
   2239             if (kDebugTableSuperNoisy) {
   2240                 ALOGI("Comparing this %dx%d to other %dx%d in %dx%d: myDelta=%d otherDelta=%d",
   2241                         screenWidthDp, screenHeightDp, o.screenWidthDp, o.screenHeightDp,
   2242                         requested->screenWidthDp, requested->screenHeightDp, myDelta, otherDelta);
   2243             }
   2244             if (myDelta != otherDelta) {
   2245                 return myDelta < otherDelta;
   2246             }
   2247         }
   2248 
   2249         if (screenLayout || o.screenLayout) {
   2250             if (((screenLayout^o.screenLayout) & MASK_SCREENSIZE) != 0
   2251                     && (requested->screenLayout & MASK_SCREENSIZE)) {
   2252                 // A little backwards compatibility here: undefined is
   2253                 // considered equivalent to normal.  But only if the
   2254                 // requested size is at least normal; otherwise, small
   2255                 // is better than the default.
   2256                 int mySL = (screenLayout & MASK_SCREENSIZE);
   2257                 int oSL = (o.screenLayout & MASK_SCREENSIZE);
   2258                 int fixedMySL = mySL;
   2259                 int fixedOSL = oSL;
   2260                 if ((requested->screenLayout & MASK_SCREENSIZE) >= SCREENSIZE_NORMAL) {
   2261                     if (fixedMySL == 0) fixedMySL = SCREENSIZE_NORMAL;
   2262                     if (fixedOSL == 0) fixedOSL = SCREENSIZE_NORMAL;
   2263                 }
   2264                 // For screen size, the best match is the one that is
   2265                 // closest to the requested screen size, but not over
   2266                 // (the not over part is dealt with in match() below).
   2267                 if (fixedMySL == fixedOSL) {
   2268                     // If the two are the same, but 'this' is actually
   2269                     // undefined, then the other is really a better match.
   2270                     if (mySL == 0) return false;
   2271                     return true;
   2272                 }
   2273                 if (fixedMySL != fixedOSL) {
   2274                     return fixedMySL > fixedOSL;
   2275                 }
   2276             }
   2277             if (((screenLayout^o.screenLayout) & MASK_SCREENLONG) != 0
   2278                     && (requested->screenLayout & MASK_SCREENLONG)) {
   2279                 return (screenLayout & MASK_SCREENLONG);
   2280             }
   2281         }
   2282 
   2283         if (screenLayout2 || o.screenLayout2) {
   2284             if (((screenLayout2^o.screenLayout2) & MASK_SCREENROUND) != 0 &&
   2285                     (requested->screenLayout2 & MASK_SCREENROUND)) {
   2286                 return screenLayout2 & MASK_SCREENROUND;
   2287             }
   2288         }
   2289 
   2290         if ((orientation != o.orientation) && requested->orientation) {
   2291             return (orientation);
   2292         }
   2293 
   2294         if (uiMode || o.uiMode) {
   2295             if (((uiMode^o.uiMode) & MASK_UI_MODE_TYPE) != 0
   2296                     && (requested->uiMode & MASK_UI_MODE_TYPE)) {
   2297                 return (uiMode & MASK_UI_MODE_TYPE);
   2298             }
   2299             if (((uiMode^o.uiMode) & MASK_UI_MODE_NIGHT) != 0
   2300                     && (requested->uiMode & MASK_UI_MODE_NIGHT)) {
   2301                 return (uiMode & MASK_UI_MODE_NIGHT);
   2302             }
   2303         }
   2304 
   2305         if (screenType || o.screenType) {
   2306             if (density != o.density) {
   2307                 // Use the system default density (DENSITY_MEDIUM, 160dpi) if none specified.
   2308                 const int thisDensity = density ? density : int(ResTable_config::DENSITY_MEDIUM);
   2309                 const int otherDensity = o.density ? o.density : int(ResTable_config::DENSITY_MEDIUM);
   2310 
   2311                 // We always prefer DENSITY_ANY over scaling a density bucket.
   2312                 if (thisDensity == ResTable_config::DENSITY_ANY) {
   2313                     return true;
   2314                 } else if (otherDensity == ResTable_config::DENSITY_ANY) {
   2315                     return false;
   2316                 }
   2317 
   2318                 int requestedDensity = requested->density;
   2319                 if (requested->density == 0 ||
   2320                         requested->density == ResTable_config::DENSITY_ANY) {
   2321                     requestedDensity = ResTable_config::DENSITY_MEDIUM;
   2322                 }
   2323 
   2324                 // DENSITY_ANY is now dealt with. We should look to
   2325                 // pick a density bucket and potentially scale it.
   2326                 // Any density is potentially useful
   2327                 // because the system will scale it.  Scaling down
   2328                 // is generally better than scaling up.
   2329                 int h = thisDensity;
   2330                 int l = otherDensity;
   2331                 bool bImBigger = true;
   2332                 if (l > h) {
   2333                     int t = h;
   2334                     h = l;
   2335                     l = t;
   2336                     bImBigger = false;
   2337                 }
   2338 
   2339                 if (requestedDensity >= h) {
   2340                     // requested value higher than both l and h, give h
   2341                     return bImBigger;
   2342                 }
   2343                 if (l >= requestedDensity) {
   2344                     // requested value lower than both l and h, give l
   2345                     return !bImBigger;
   2346                 }
   2347                 // saying that scaling down is 2x better than up
   2348                 if (((2 * l) - requestedDensity) * h > requestedDensity * requestedDensity) {
   2349                     return !bImBigger;
   2350                 } else {
   2351                     return bImBigger;
   2352                 }
   2353             }
   2354 
   2355             if ((touchscreen != o.touchscreen) && requested->touchscreen) {
   2356                 return (touchscreen);
   2357             }
   2358         }
   2359 
   2360         if (input || o.input) {
   2361             const int keysHidden = inputFlags & MASK_KEYSHIDDEN;
   2362             const int oKeysHidden = o.inputFlags & MASK_KEYSHIDDEN;
   2363             if (keysHidden != oKeysHidden) {
   2364                 const int reqKeysHidden =
   2365                         requested->inputFlags & MASK_KEYSHIDDEN;
   2366                 if (reqKeysHidden) {
   2367 
   2368                     if (!keysHidden) return false;
   2369                     if (!oKeysHidden) return true;
   2370                     // For compatibility, we count KEYSHIDDEN_NO as being
   2371                     // the same as KEYSHIDDEN_SOFT.  Here we disambiguate
   2372                     // these by making an exact match more specific.
   2373                     if (reqKeysHidden == keysHidden) return true;
   2374                     if (reqKeysHidden == oKeysHidden) return false;
   2375                 }
   2376             }
   2377 
   2378             const int navHidden = inputFlags & MASK_NAVHIDDEN;
   2379             const int oNavHidden = o.inputFlags & MASK_NAVHIDDEN;
   2380             if (navHidden != oNavHidden) {
   2381                 const int reqNavHidden =
   2382                         requested->inputFlags & MASK_NAVHIDDEN;
   2383                 if (reqNavHidden) {
   2384 
   2385                     if (!navHidden) return false;
   2386                     if (!oNavHidden) return true;
   2387                 }
   2388             }
   2389 
   2390             if ((keyboard != o.keyboard) && requested->keyboard) {
   2391                 return (keyboard);
   2392             }
   2393 
   2394             if ((navigation != o.navigation) && requested->navigation) {
   2395                 return (navigation);
   2396             }
   2397         }
   2398 
   2399         if (screenSize || o.screenSize) {
   2400             // "Better" is based on the sum of the difference between both
   2401             // width and height from the requested dimensions.  We are
   2402             // assuming the invalid configs (with smaller sizes) have
   2403             // already been filtered.  Note that if a particular dimension
   2404             // is unspecified, we will end up with a large value (the
   2405             // difference between 0 and the requested dimension), which is
   2406             // good since we will prefer a config that has specified a
   2407             // size value.
   2408             int myDelta = 0, otherDelta = 0;
   2409             if (requested->screenWidth) {
   2410                 myDelta += requested->screenWidth - screenWidth;
   2411                 otherDelta += requested->screenWidth - o.screenWidth;
   2412             }
   2413             if (requested->screenHeight) {
   2414                 myDelta += requested->screenHeight - screenHeight;
   2415                 otherDelta += requested->screenHeight - o.screenHeight;
   2416             }
   2417             if (myDelta != otherDelta) {
   2418                 return myDelta < otherDelta;
   2419             }
   2420         }
   2421 
   2422         if (version || o.version) {
   2423             if ((sdkVersion != o.sdkVersion) && requested->sdkVersion) {
   2424                 return (sdkVersion > o.sdkVersion);
   2425             }
   2426 
   2427             if ((minorVersion != o.minorVersion) &&
   2428                     requested->minorVersion) {
   2429                 return (minorVersion);
   2430             }
   2431         }
   2432 
   2433         return false;
   2434     }
   2435     return isMoreSpecificThan(o);
   2436 }
   2437 
   2438 bool ResTable_config::match(const ResTable_config& settings) const {
   2439     if (imsi != 0) {
   2440         if (mcc != 0 && mcc != settings.mcc) {
   2441             return false;
   2442         }
   2443         if (mnc != 0 && mnc != settings.mnc) {
   2444             return false;
   2445         }
   2446     }
   2447     if (locale != 0) {
   2448         // Don't consider the script & variants when deciding matches.
   2449         //
   2450         // If we two configs differ only in their script or language, they
   2451         // can be weeded out in the isMoreSpecificThan test.
   2452         if (language[0] != 0
   2453             && (language[0] != settings.language[0]
   2454                 || language[1] != settings.language[1])) {
   2455             return false;
   2456         }
   2457 
   2458         if (country[0] != 0
   2459             && (country[0] != settings.country[0]
   2460                 || country[1] != settings.country[1])) {
   2461             return false;
   2462         }
   2463     }
   2464 
   2465     if (screenConfig != 0) {
   2466         const int layoutDir = screenLayout&MASK_LAYOUTDIR;
   2467         const int setLayoutDir = settings.screenLayout&MASK_LAYOUTDIR;
   2468         if (layoutDir != 0 && layoutDir != setLayoutDir) {
   2469             return false;
   2470         }
   2471 
   2472         const int screenSize = screenLayout&MASK_SCREENSIZE;
   2473         const int setScreenSize = settings.screenLayout&MASK_SCREENSIZE;
   2474         // Any screen sizes for larger screens than the setting do not
   2475         // match.
   2476         if (screenSize != 0 && screenSize > setScreenSize) {
   2477             return false;
   2478         }
   2479 
   2480         const int screenLong = screenLayout&MASK_SCREENLONG;
   2481         const int setScreenLong = settings.screenLayout&MASK_SCREENLONG;
   2482         if (screenLong != 0 && screenLong != setScreenLong) {
   2483             return false;
   2484         }
   2485 
   2486         const int uiModeType = uiMode&MASK_UI_MODE_TYPE;
   2487         const int setUiModeType = settings.uiMode&MASK_UI_MODE_TYPE;
   2488         if (uiModeType != 0 && uiModeType != setUiModeType) {
   2489             return false;
   2490         }
   2491 
   2492         const int uiModeNight = uiMode&MASK_UI_MODE_NIGHT;
   2493         const int setUiModeNight = settings.uiMode&MASK_UI_MODE_NIGHT;
   2494         if (uiModeNight != 0 && uiModeNight != setUiModeNight) {
   2495             return false;
   2496         }
   2497 
   2498         if (smallestScreenWidthDp != 0
   2499                 && smallestScreenWidthDp > settings.smallestScreenWidthDp) {
   2500             return false;
   2501         }
   2502     }
   2503 
   2504     if (screenConfig2 != 0) {
   2505         const int screenRound = screenLayout2 & MASK_SCREENROUND;
   2506         const int setScreenRound = settings.screenLayout2 & MASK_SCREENROUND;
   2507         if (screenRound != 0 && screenRound != setScreenRound) {
   2508             return false;
   2509         }
   2510     }
   2511 
   2512     if (screenSizeDp != 0) {
   2513         if (screenWidthDp != 0 && screenWidthDp > settings.screenWidthDp) {
   2514             if (kDebugTableSuperNoisy) {
   2515                 ALOGI("Filtering out width %d in requested %d", screenWidthDp,
   2516                         settings.screenWidthDp);
   2517             }
   2518             return false;
   2519         }
   2520         if (screenHeightDp != 0 && screenHeightDp > settings.screenHeightDp) {
   2521             if (kDebugTableSuperNoisy) {
   2522                 ALOGI("Filtering out height %d in requested %d", screenHeightDp,
   2523                         settings.screenHeightDp);
   2524             }
   2525             return false;
   2526         }
   2527     }
   2528     if (screenType != 0) {
   2529         if (orientation != 0 && orientation != settings.orientation) {
   2530             return false;
   2531         }
   2532         // density always matches - we can scale it.  See isBetterThan
   2533         if (touchscreen != 0 && touchscreen != settings.touchscreen) {
   2534             return false;
   2535         }
   2536     }
   2537     if (input != 0) {
   2538         const int keysHidden = inputFlags&MASK_KEYSHIDDEN;
   2539         const int setKeysHidden = settings.inputFlags&MASK_KEYSHIDDEN;
   2540         if (keysHidden != 0 && keysHidden != setKeysHidden) {
   2541             // For compatibility, we count a request for KEYSHIDDEN_NO as also
   2542             // matching the more recent KEYSHIDDEN_SOFT.  Basically
   2543             // KEYSHIDDEN_NO means there is some kind of keyboard available.
   2544             if (kDebugTableSuperNoisy) {
   2545                 ALOGI("Matching keysHidden: have=%d, config=%d\n", keysHidden, setKeysHidden);
   2546             }
   2547             if (keysHidden != KEYSHIDDEN_NO || setKeysHidden != KEYSHIDDEN_SOFT) {
   2548                 if (kDebugTableSuperNoisy) {
   2549                     ALOGI("No match!");
   2550                 }
   2551                 return false;
   2552             }
   2553         }
   2554         const int navHidden = inputFlags&MASK_NAVHIDDEN;
   2555         const int setNavHidden = settings.inputFlags&MASK_NAVHIDDEN;
   2556         if (navHidden != 0 && navHidden != setNavHidden) {
   2557             return false;
   2558         }
   2559         if (keyboard != 0 && keyboard != settings.keyboard) {
   2560             return false;
   2561         }
   2562         if (navigation != 0 && navigation != settings.navigation) {
   2563             return false;
   2564         }
   2565     }
   2566     if (screenSize != 0) {
   2567         if (screenWidth != 0 && screenWidth > settings.screenWidth) {
   2568             return false;
   2569         }
   2570         if (screenHeight != 0 && screenHeight > settings.screenHeight) {
   2571             return false;
   2572         }
   2573     }
   2574     if (version != 0) {
   2575         if (sdkVersion != 0 && sdkVersion > settings.sdkVersion) {
   2576             return false;
   2577         }
   2578         if (minorVersion != 0 && minorVersion != settings.minorVersion) {
   2579             return false;
   2580         }
   2581     }
   2582     return true;
   2583 }
   2584 
   2585 void ResTable_config::appendDirLocale(String8& out) const {
   2586     if (!language[0]) {
   2587         return;
   2588     }
   2589 
   2590     if (!localeScript[0] && !localeVariant[0]) {
   2591         // Legacy format.
   2592         if (out.size() > 0) {
   2593             out.append("-");
   2594         }
   2595 
   2596         char buf[4];
   2597         size_t len = unpackLanguage(buf);
   2598         out.append(buf, len);
   2599 
   2600         if (country[0]) {
   2601             out.append("-r");
   2602             len = unpackRegion(buf);
   2603             out.append(buf, len);
   2604         }
   2605         return;
   2606     }
   2607 
   2608     // We are writing the modified bcp47 tag.
   2609     // It starts with 'b+' and uses '+' as a separator.
   2610 
   2611     if (out.size() > 0) {
   2612         out.append("-");
   2613     }
   2614     out.append("b+");
   2615 
   2616     char buf[4];
   2617     size_t len = unpackLanguage(buf);
   2618     out.append(buf, len);
   2619 
   2620     if (localeScript[0]) {
   2621         out.append("+");
   2622         out.append(localeScript, sizeof(localeScript));
   2623     }
   2624 
   2625     if (country[0]) {
   2626         out.append("+");
   2627         len = unpackRegion(buf);
   2628         out.append(buf, len);
   2629     }
   2630 
   2631     if (localeVariant[0]) {
   2632         out.append("+");
   2633         out.append(localeVariant, sizeof(localeVariant));
   2634     }
   2635 }
   2636 
   2637 void ResTable_config::getBcp47Locale(char str[RESTABLE_MAX_LOCALE_LEN]) const {
   2638     memset(str, 0, RESTABLE_MAX_LOCALE_LEN);
   2639 
   2640     // This represents the "any" locale value, which has traditionally been
   2641     // represented by the empty string.
   2642     if (!language[0] && !country[0]) {
   2643         return;
   2644     }
   2645 
   2646     size_t charsWritten = 0;
   2647     if (language[0]) {
   2648         charsWritten += unpackLanguage(str);
   2649     }
   2650 
   2651     if (localeScript[0]) {
   2652         if (charsWritten) {
   2653             str[charsWritten++] = '-';
   2654         }
   2655         memcpy(str + charsWritten, localeScript, sizeof(localeScript));
   2656         charsWritten += sizeof(localeScript);
   2657     }
   2658 
   2659     if (country[0]) {
   2660         if (charsWritten) {
   2661             str[charsWritten++] = '-';
   2662         }
   2663         charsWritten += unpackRegion(str + charsWritten);
   2664     }
   2665 
   2666     if (localeVariant[0]) {
   2667         if (charsWritten) {
   2668             str[charsWritten++] = '-';
   2669         }
   2670         memcpy(str + charsWritten, localeVariant, sizeof(localeVariant));
   2671     }
   2672 }
   2673 
   2674 /* static */ inline bool assignLocaleComponent(ResTable_config* config,
   2675         const char* start, size_t size) {
   2676 
   2677   switch (size) {
   2678        case 0:
   2679            return false;
   2680        case 2:
   2681        case 3:
   2682            config->language[0] ? config->packRegion(start) : config->packLanguage(start);
   2683            break;
   2684        case 4:
   2685            config->localeScript[0] = toupper(start[0]);
   2686            for (size_t i = 1; i < 4; ++i) {
   2687                config->localeScript[i] = tolower(start[i]);
   2688            }
   2689            break;
   2690        case 5:
   2691        case 6:
   2692        case 7:
   2693        case 8:
   2694            for (size_t i = 0; i < size; ++i) {
   2695                config->localeVariant[i] = tolower(start[i]);
   2696            }
   2697            break;
   2698        default:
   2699            return false;
   2700   }
   2701 
   2702   return true;
   2703 }
   2704 
   2705 void ResTable_config::setBcp47Locale(const char* in) {
   2706     locale = 0;
   2707     memset(localeScript, 0, sizeof(localeScript));
   2708     memset(localeVariant, 0, sizeof(localeVariant));
   2709 
   2710     const char* separator = in;
   2711     const char* start = in;
   2712     while ((separator = strchr(start, '-')) != NULL) {
   2713         const size_t size = separator - start;
   2714         if (!assignLocaleComponent(this, start, size)) {
   2715             fprintf(stderr, "Invalid BCP-47 locale string: %s", in);
   2716         }
   2717 
   2718         start = (separator + 1);
   2719     }
   2720 
   2721     const size_t size = in + strlen(in) - start;
   2722     assignLocaleComponent(this, start, size);
   2723 }
   2724 
   2725 String8 ResTable_config::toString() const {
   2726     String8 res;
   2727 
   2728     if (mcc != 0) {
   2729         if (res.size() > 0) res.append("-");
   2730         res.appendFormat("mcc%d", dtohs(mcc));
   2731     }
   2732     if (mnc != 0) {
   2733         if (res.size() > 0) res.append("-");
   2734         res.appendFormat("mnc%d", dtohs(mnc));
   2735     }
   2736 
   2737     appendDirLocale(res);
   2738 
   2739     if ((screenLayout&MASK_LAYOUTDIR) != 0) {
   2740         if (res.size() > 0) res.append("-");
   2741         switch (screenLayout&ResTable_config::MASK_LAYOUTDIR) {
   2742             case ResTable_config::LAYOUTDIR_LTR:
   2743                 res.append("ldltr");
   2744                 break;
   2745             case ResTable_config::LAYOUTDIR_RTL:
   2746                 res.append("ldrtl");
   2747                 break;
   2748             default:
   2749                 res.appendFormat("layoutDir=%d",
   2750                         dtohs(screenLayout&ResTable_config::MASK_LAYOUTDIR));
   2751                 break;
   2752         }
   2753     }
   2754     if (smallestScreenWidthDp != 0) {
   2755         if (res.size() > 0) res.append("-");
   2756         res.appendFormat("sw%ddp", dtohs(smallestScreenWidthDp));
   2757     }
   2758     if (screenWidthDp != 0) {
   2759         if (res.size() > 0) res.append("-");
   2760         res.appendFormat("w%ddp", dtohs(screenWidthDp));
   2761     }
   2762     if (screenHeightDp != 0) {
   2763         if (res.size() > 0) res.append("-");
   2764         res.appendFormat("h%ddp", dtohs(screenHeightDp));
   2765     }
   2766     if ((screenLayout&MASK_SCREENSIZE) != SCREENSIZE_ANY) {
   2767         if (res.size() > 0) res.append("-");
   2768         switch (screenLayout&ResTable_config::MASK_SCREENSIZE) {
   2769             case ResTable_config::SCREENSIZE_SMALL:
   2770                 res.append("small");
   2771                 break;
   2772             case ResTable_config::SCREENSIZE_NORMAL:
   2773                 res.append("normal");
   2774                 break;
   2775             case ResTable_config::SCREENSIZE_LARGE:
   2776                 res.append("large");
   2777                 break;
   2778             case ResTable_config::SCREENSIZE_XLARGE:
   2779                 res.append("xlarge");
   2780                 break;
   2781             default:
   2782                 res.appendFormat("screenLayoutSize=%d",
   2783                         dtohs(screenLayout&ResTable_config::MASK_SCREENSIZE));
   2784                 break;
   2785         }
   2786     }
   2787     if ((screenLayout&MASK_SCREENLONG) != 0) {
   2788         if (res.size() > 0) res.append("-");
   2789         switch (screenLayout&ResTable_config::MASK_SCREENLONG) {
   2790             case ResTable_config::SCREENLONG_NO:
   2791                 res.append("notlong");
   2792                 break;
   2793             case ResTable_config::SCREENLONG_YES:
   2794                 res.append("long");
   2795                 break;
   2796             default:
   2797                 res.appendFormat("screenLayoutLong=%d",
   2798                         dtohs(screenLayout&ResTable_config::MASK_SCREENLONG));
   2799                 break;
   2800         }
   2801     }
   2802     if ((screenLayout2&MASK_SCREENROUND) != 0) {
   2803         if (res.size() > 0) res.append("-");
   2804         switch (screenLayout2&MASK_SCREENROUND) {
   2805             case SCREENROUND_NO:
   2806                 res.append("notround");
   2807                 break;
   2808             case SCREENROUND_YES:
   2809                 res.append("round");
   2810                 break;
   2811             default:
   2812                 res.appendFormat("screenRound=%d", dtohs(screenLayout2&MASK_SCREENROUND));
   2813                 break;
   2814         }
   2815     }
   2816     if (orientation != ORIENTATION_ANY) {
   2817         if (res.size() > 0) res.append("-");
   2818         switch (orientation) {
   2819             case ResTable_config::ORIENTATION_PORT:
   2820                 res.append("port");
   2821                 break;
   2822             case ResTable_config::ORIENTATION_LAND:
   2823                 res.append("land");
   2824                 break;
   2825             case ResTable_config::ORIENTATION_SQUARE:
   2826                 res.append("square");
   2827                 break;
   2828             default:
   2829                 res.appendFormat("orientation=%d", dtohs(orientation));
   2830                 break;
   2831         }
   2832     }
   2833     if ((uiMode&MASK_UI_MODE_TYPE) != UI_MODE_TYPE_ANY) {
   2834         if (res.size() > 0) res.append("-");
   2835         switch (uiMode&ResTable_config::MASK_UI_MODE_TYPE) {
   2836             case ResTable_config::UI_MODE_TYPE_DESK:
   2837                 res.append("desk");
   2838                 break;
   2839             case ResTable_config::UI_MODE_TYPE_CAR:
   2840                 res.append("car");
   2841                 break;
   2842             case ResTable_config::UI_MODE_TYPE_TELEVISION:
   2843                 res.append("television");
   2844                 break;
   2845             case ResTable_config::UI_MODE_TYPE_APPLIANCE:
   2846                 res.append("appliance");
   2847                 break;
   2848             case ResTable_config::UI_MODE_TYPE_WATCH:
   2849                 res.append("watch");
   2850                 break;
   2851             default:
   2852                 res.appendFormat("uiModeType=%d",
   2853                         dtohs(screenLayout&ResTable_config::MASK_UI_MODE_TYPE));
   2854                 break;
   2855         }
   2856     }
   2857     if ((uiMode&MASK_UI_MODE_NIGHT) != 0) {
   2858         if (res.size() > 0) res.append("-");
   2859         switch (uiMode&ResTable_config::MASK_UI_MODE_NIGHT) {
   2860             case ResTable_config::UI_MODE_NIGHT_NO:
   2861                 res.append("notnight");
   2862                 break;
   2863             case ResTable_config::UI_MODE_NIGHT_YES:
   2864                 res.append("night");
   2865                 break;
   2866             default:
   2867                 res.appendFormat("uiModeNight=%d",
   2868                         dtohs(uiMode&MASK_UI_MODE_NIGHT));
   2869                 break;
   2870         }
   2871     }
   2872     if (density != DENSITY_DEFAULT) {
   2873         if (res.size() > 0) res.append("-");
   2874         switch (density) {
   2875             case ResTable_config::DENSITY_LOW:
   2876                 res.append("ldpi");
   2877                 break;
   2878             case ResTable_config::DENSITY_MEDIUM:
   2879                 res.append("mdpi");
   2880                 break;
   2881             case ResTable_config::DENSITY_TV:
   2882                 res.append("tvdpi");
   2883                 break;
   2884             case ResTable_config::DENSITY_HIGH:
   2885                 res.append("hdpi");
   2886                 break;
   2887             case ResTable_config::DENSITY_XHIGH:
   2888                 res.append("xhdpi");
   2889                 break;
   2890             case ResTable_config::DENSITY_XXHIGH:
   2891                 res.append("xxhdpi");
   2892                 break;
   2893             case ResTable_config::DENSITY_XXXHIGH:
   2894                 res.append("xxxhdpi");
   2895                 break;
   2896             case ResTable_config::DENSITY_NONE:
   2897                 res.append("nodpi");
   2898                 break;
   2899             case ResTable_config::DENSITY_ANY:
   2900                 res.append("anydpi");
   2901                 break;
   2902             default:
   2903                 res.appendFormat("%ddpi", dtohs(density));
   2904                 break;
   2905         }
   2906     }
   2907     if (touchscreen != TOUCHSCREEN_ANY) {
   2908         if (res.size() > 0) res.append("-");
   2909         switch (touchscreen) {
   2910             case ResTable_config::TOUCHSCREEN_NOTOUCH:
   2911                 res.append("notouch");
   2912                 break;
   2913             case ResTable_config::TOUCHSCREEN_FINGER:
   2914                 res.append("finger");
   2915                 break;
   2916             case ResTable_config::TOUCHSCREEN_STYLUS:
   2917                 res.append("stylus");
   2918                 break;
   2919             default:
   2920                 res.appendFormat("touchscreen=%d", dtohs(touchscreen));
   2921                 break;
   2922         }
   2923     }
   2924     if ((inputFlags&MASK_KEYSHIDDEN) != 0) {
   2925         if (res.size() > 0) res.append("-");
   2926         switch (inputFlags&MASK_KEYSHIDDEN) {
   2927             case ResTable_config::KEYSHIDDEN_NO:
   2928                 res.append("keysexposed");
   2929                 break;
   2930             case ResTable_config::KEYSHIDDEN_YES:
   2931                 res.append("keyshidden");
   2932                 break;
   2933             case ResTable_config::KEYSHIDDEN_SOFT:
   2934                 res.append("keyssoft");
   2935                 break;
   2936         }
   2937     }
   2938     if (keyboard != KEYBOARD_ANY) {
   2939         if (res.size() > 0) res.append("-");
   2940         switch (keyboard) {
   2941             case ResTable_config::KEYBOARD_NOKEYS:
   2942                 res.append("nokeys");
   2943                 break;
   2944             case ResTable_config::KEYBOARD_QWERTY:
   2945                 res.append("qwerty");
   2946                 break;
   2947             case ResTable_config::KEYBOARD_12KEY:
   2948                 res.append("12key");
   2949                 break;
   2950             default:
   2951                 res.appendFormat("keyboard=%d", dtohs(keyboard));
   2952                 break;
   2953         }
   2954     }
   2955     if ((inputFlags&MASK_NAVHIDDEN) != 0) {
   2956         if (res.size() > 0) res.append("-");
   2957         switch (inputFlags&MASK_NAVHIDDEN) {
   2958             case ResTable_config::NAVHIDDEN_NO:
   2959                 res.append("navexposed");
   2960                 break;
   2961             case ResTable_config::NAVHIDDEN_YES:
   2962                 res.append("navhidden");
   2963                 break;
   2964             default:
   2965                 res.appendFormat("inputFlagsNavHidden=%d",
   2966                         dtohs(inputFlags&MASK_NAVHIDDEN));
   2967                 break;
   2968         }
   2969     }
   2970     if (navigation != NAVIGATION_ANY) {
   2971         if (res.size() > 0) res.append("-");
   2972         switch (navigation) {
   2973             case ResTable_config::NAVIGATION_NONAV:
   2974                 res.append("nonav");
   2975                 break;
   2976             case ResTable_config::NAVIGATION_DPAD:
   2977                 res.append("dpad");
   2978                 break;
   2979             case ResTable_config::NAVIGATION_TRACKBALL:
   2980                 res.append("trackball");
   2981                 break;
   2982             case ResTable_config::NAVIGATION_WHEEL:
   2983                 res.append("wheel");
   2984                 break;
   2985             default:
   2986                 res.appendFormat("navigation=%d", dtohs(navigation));
   2987                 break;
   2988         }
   2989     }
   2990     if (screenSize != 0) {
   2991         if (res.size() > 0) res.append("-");
   2992         res.appendFormat("%dx%d", dtohs(screenWidth), dtohs(screenHeight));
   2993     }
   2994     if (version != 0) {
   2995         if (res.size() > 0) res.append("-");
   2996         res.appendFormat("v%d", dtohs(sdkVersion));
   2997         if (minorVersion != 0) {
   2998             res.appendFormat(".%d", dtohs(minorVersion));
   2999         }
   3000     }
   3001 
   3002     return res;
   3003 }
   3004 
   3005 // --------------------------------------------------------------------
   3006 // --------------------------------------------------------------------
   3007 // --------------------------------------------------------------------
   3008 
   3009 struct ResTable::Header
   3010 {
   3011     Header(ResTable* _owner) : owner(_owner), ownedData(NULL), header(NULL),
   3012         resourceIDMap(NULL), resourceIDMapSize(0) { }
   3013 
   3014     ~Header()
   3015     {
   3016         free(resourceIDMap);
   3017     }
   3018 
   3019     const ResTable* const           owner;
   3020     void*                           ownedData;
   3021     const ResTable_header*          header;
   3022     size_t                          size;
   3023     const uint8_t*                  dataEnd;
   3024     size_t                          index;
   3025     int32_t                         cookie;
   3026 
   3027     ResStringPool                   values;
   3028     uint32_t*                       resourceIDMap;
   3029     size_t                          resourceIDMapSize;
   3030 };
   3031 
   3032 struct ResTable::Entry {
   3033     ResTable_config config;
   3034     const ResTable_entry* entry;
   3035     const ResTable_type* type;
   3036     uint32_t specFlags;
   3037     const Package* package;
   3038 
   3039     StringPoolRef typeStr;
   3040     StringPoolRef keyStr;
   3041 };
   3042 
   3043 struct ResTable::Type
   3044 {
   3045     Type(const Header* _header, const Package* _package, size_t count)
   3046         : header(_header), package(_package), entryCount(count),
   3047           typeSpec(NULL), typeSpecFlags(NULL) { }
   3048     const Header* const             header;
   3049     const Package* const            package;
   3050     const size_t                    entryCount;
   3051     const ResTable_typeSpec*        typeSpec;
   3052     const uint32_t*                 typeSpecFlags;
   3053     IdmapEntries                    idmapEntries;
   3054     Vector<const ResTable_type*>    configs;
   3055 };
   3056 
   3057 struct ResTable::Package
   3058 {
   3059     Package(ResTable* _owner, const Header* _header, const ResTable_package* _package)
   3060         : owner(_owner), header(_header), package(_package), typeIdOffset(0) {
   3061         if (dtohs(package->header.headerSize) == sizeof(package)) {
   3062             // The package structure is the same size as the definition.
   3063             // This means it contains the typeIdOffset field.
   3064             typeIdOffset = package->typeIdOffset;
   3065         }
   3066     }
   3067 
   3068     const ResTable* const           owner;
   3069     const Header* const             header;
   3070     const ResTable_package* const   package;
   3071 
   3072     ResStringPool                   typeStrings;
   3073     ResStringPool                   keyStrings;
   3074 
   3075     size_t                          typeIdOffset;
   3076 };
   3077 
   3078 // A group of objects describing a particular resource package.
   3079 // The first in 'package' is always the root object (from the resource
   3080 // table that defined the package); the ones after are skins on top of it.
   3081 struct ResTable::PackageGroup
   3082 {
   3083     PackageGroup(ResTable* _owner, const String16& _name, uint32_t _id)
   3084         : owner(_owner)
   3085         , name(_name)
   3086         , id(_id)
   3087         , largestTypeId(0)
   3088         , bags(NULL)
   3089         , dynamicRefTable(static_cast<uint8_t>(_id))
   3090     { }
   3091 
   3092     ~PackageGroup() {
   3093         clearBagCache();
   3094         const size_t numTypes = types.size();
   3095         for (size_t i = 0; i < numTypes; i++) {
   3096             const TypeList& typeList = types[i];
   3097             const size_t numInnerTypes = typeList.size();
   3098             for (size_t j = 0; j < numInnerTypes; j++) {
   3099                 if (typeList[j]->package->owner == owner) {
   3100                     delete typeList[j];
   3101                 }
   3102             }
   3103         }
   3104 
   3105         const size_t N = packages.size();
   3106         for (size_t i=0; i<N; i++) {
   3107             Package* pkg = packages[i];
   3108             if (pkg->owner == owner) {
   3109                 delete pkg;
   3110             }
   3111         }
   3112     }
   3113 
   3114     void clearBagCache() {
   3115         if (bags) {
   3116             if (kDebugTableNoisy) {
   3117                 printf("bags=%p\n", bags);
   3118             }
   3119             for (size_t i = 0; i < bags->size(); i++) {
   3120                 if (kDebugTableNoisy) {
   3121                     printf("type=%zu\n", i);
   3122                 }
   3123                 const TypeList& typeList = types[i];
   3124                 if (!typeList.isEmpty()) {
   3125                     bag_set** typeBags = bags->get(i);
   3126                     if (kDebugTableNoisy) {
   3127                         printf("typeBags=%p\n", typeBags);
   3128                     }
   3129                     if (typeBags) {
   3130                         const size_t N = typeList[0]->entryCount;
   3131                         if (kDebugTableNoisy) {
   3132                             printf("type->entryCount=%zu\n", N);
   3133                         }
   3134                         for (size_t j = 0; j < N; j++) {
   3135                             if (typeBags[j] && typeBags[j] != (bag_set*)0xFFFFFFFF)
   3136                                 free(typeBags[j]);
   3137                         }
   3138                         free(typeBags);
   3139                     }
   3140                 }
   3141             }
   3142             delete bags;
   3143             bags = NULL;
   3144         }
   3145     }
   3146 
   3147     ssize_t findType16(const char16_t* type, size_t len) const {
   3148         const size_t N = packages.size();
   3149         for (size_t i = 0; i < N; i++) {
   3150             ssize_t index = packages[i]->typeStrings.indexOfString(type, len);
   3151             if (index >= 0) {
   3152                 return index + packages[i]->typeIdOffset;
   3153             }
   3154         }
   3155         return -1;
   3156     }
   3157 
   3158     const ResTable* const           owner;
   3159     String16 const                  name;
   3160     uint32_t const                  id;
   3161 
   3162     // This is mainly used to keep track of the loaded packages
   3163     // and to clean them up properly. Accessing resources happens from
   3164     // the 'types' array.
   3165     Vector<Package*>                packages;
   3166 
   3167     ByteBucketArray<TypeList>       types;
   3168 
   3169     uint8_t                         largestTypeId;
   3170 
   3171     // Computed attribute bags, first indexed by the type and second
   3172     // by the entry in that type.
   3173     ByteBucketArray<bag_set**>*     bags;
   3174 
   3175     // The table mapping dynamic references to resolved references for
   3176     // this package group.
   3177     // TODO: We may be able to support dynamic references in overlays
   3178     // by having these tables in a per-package scope rather than
   3179     // per-package-group.
   3180     DynamicRefTable                 dynamicRefTable;
   3181 };
   3182 
   3183 struct ResTable::bag_set
   3184 {
   3185     size_t numAttrs;    // number in array
   3186     size_t availAttrs;  // total space in array
   3187     uint32_t typeSpecFlags;
   3188     // Followed by 'numAttr' bag_entry structures.
   3189 };
   3190 
   3191 ResTable::Theme::Theme(const ResTable& table)
   3192     : mTable(table)
   3193     , mTypeSpecFlags(0)
   3194 {
   3195     memset(mPackages, 0, sizeof(mPackages));
   3196 }
   3197 
   3198 ResTable::Theme::~Theme()
   3199 {
   3200     for (size_t i=0; i<Res_MAXPACKAGE; i++) {
   3201         package_info* pi = mPackages[i];
   3202         if (pi != NULL) {
   3203             free_package(pi);
   3204         }
   3205     }
   3206 }
   3207 
   3208 void ResTable::Theme::free_package(package_info* pi)
   3209 {
   3210     for (size_t j = 0; j <= Res_MAXTYPE; j++) {
   3211         theme_entry* te = pi->types[j].entries;
   3212         if (te != NULL) {
   3213             free(te);
   3214         }
   3215     }
   3216     free(pi);
   3217 }
   3218 
   3219 ResTable::Theme::package_info* ResTable::Theme::copy_package(package_info* pi)
   3220 {
   3221     package_info* newpi = (package_info*)malloc(sizeof(package_info));
   3222     for (size_t j = 0; j <= Res_MAXTYPE; j++) {
   3223         size_t cnt = pi->types[j].numEntries;
   3224         newpi->types[j].numEntries = cnt;
   3225         theme_entry* te = pi->types[j].entries;
   3226         size_t cnt_max = SIZE_MAX / sizeof(theme_entry);
   3227         if (te != NULL && (cnt < 0xFFFFFFFF-1) && (cnt < cnt_max)) {
   3228             theme_entry* newte = (theme_entry*)malloc(cnt*sizeof(theme_entry));
   3229             newpi->types[j].entries = newte;
   3230             memcpy(newte, te, cnt*sizeof(theme_entry));
   3231         } else {
   3232             newpi->types[j].entries = NULL;
   3233         }
   3234     }
   3235     return newpi;
   3236 }
   3237 
   3238 status_t ResTable::Theme::applyStyle(uint32_t resID, bool force)
   3239 {
   3240     const bag_entry* bag;
   3241     uint32_t bagTypeSpecFlags = 0;
   3242     mTable.lock();
   3243     const ssize_t N = mTable.getBagLocked(resID, &bag, &bagTypeSpecFlags);
   3244     if (kDebugTableNoisy) {
   3245         ALOGV("Applying style 0x%08x to theme %p, count=%zu", resID, this, N);
   3246     }
   3247     if (N < 0) {
   3248         mTable.unlock();
   3249         return N;
   3250     }
   3251 
   3252     mTypeSpecFlags |= bagTypeSpecFlags;
   3253 
   3254     uint32_t curPackage = 0xffffffff;
   3255     ssize_t curPackageIndex = 0;
   3256     package_info* curPI = NULL;
   3257     uint32_t curType = 0xffffffff;
   3258     size_t numEntries = 0;
   3259     theme_entry* curEntries = NULL;
   3260 
   3261     const bag_entry* end = bag + N;
   3262     while (bag < end) {
   3263         const uint32_t attrRes = bag->map.name.ident;
   3264         const uint32_t p = Res_GETPACKAGE(attrRes);
   3265         const uint32_t t = Res_GETTYPE(attrRes);
   3266         const uint32_t e = Res_GETENTRY(attrRes);
   3267 
   3268         if (curPackage != p) {
   3269             const ssize_t pidx = mTable.getResourcePackageIndex(attrRes);
   3270             if (pidx < 0) {
   3271                 ALOGE("Style contains key with bad package: 0x%08x\n", attrRes);
   3272                 bag++;
   3273                 continue;
   3274             }
   3275             curPackage = p;
   3276             curPackageIndex = pidx;
   3277             curPI = mPackages[pidx];
   3278             if (curPI == NULL) {
   3279                 curPI = (package_info*)malloc(sizeof(package_info));
   3280                 memset(curPI, 0, sizeof(*curPI));
   3281                 mPackages[pidx] = curPI;
   3282             }
   3283             curType = 0xffffffff;
   3284         }
   3285         if (curType != t) {
   3286             if (t > Res_MAXTYPE) {
   3287                 ALOGE("Style contains key with bad type: 0x%08x\n", attrRes);
   3288                 bag++;
   3289                 continue;
   3290             }
   3291             curType = t;
   3292             curEntries = curPI->types[t].entries;
   3293             if (curEntries == NULL) {
   3294                 PackageGroup* const grp = mTable.mPackageGroups[curPackageIndex];
   3295                 const TypeList& typeList = grp->types[t];
   3296                 size_t cnt = typeList.isEmpty() ? 0 : typeList[0]->entryCount;
   3297                 size_t cnt_max = SIZE_MAX / sizeof(theme_entry);
   3298                 size_t buff_size = (cnt < cnt_max && cnt < 0xFFFFFFFF-1) ?
   3299                                           cnt*sizeof(theme_entry) : 0;
   3300                 curEntries = (theme_entry*)malloc(buff_size);
   3301                 memset(curEntries, Res_value::TYPE_NULL, buff_size);
   3302                 curPI->types[t].numEntries = cnt;
   3303                 curPI->types[t].entries = curEntries;
   3304             }
   3305             numEntries = curPI->types[t].numEntries;
   3306         }
   3307         if (e >= numEntries) {
   3308             ALOGE("Style contains key with bad entry: 0x%08x\n", attrRes);
   3309             bag++;
   3310             continue;
   3311         }
   3312         theme_entry* curEntry = curEntries + e;
   3313         if (kDebugTableNoisy) {
   3314             ALOGV("Attr 0x%08x: type=0x%x, data=0x%08x; curType=0x%x",
   3315                     attrRes, bag->map.value.dataType, bag->map.value.data,
   3316                     curEntry->value.dataType);
   3317         }
   3318         if (force || curEntry->value.dataType == Res_value::TYPE_NULL) {
   3319             curEntry->stringBlock = bag->stringBlock;
   3320             curEntry->typeSpecFlags |= bagTypeSpecFlags;
   3321             curEntry->value = bag->map.value;
   3322         }
   3323 
   3324         bag++;
   3325     }
   3326 
   3327     mTable.unlock();
   3328 
   3329     if (kDebugTableTheme) {
   3330         ALOGI("Applying style 0x%08x (force=%d)  theme %p...\n", resID, force, this);
   3331         dumpToLog();
   3332     }
   3333 
   3334     return NO_ERROR;
   3335 }
   3336 
   3337 status_t ResTable::Theme::setTo(const Theme& other)
   3338 {
   3339     if (kDebugTableTheme) {
   3340         ALOGI("Setting theme %p from theme %p...\n", this, &other);
   3341         dumpToLog();
   3342         other.dumpToLog();
   3343     }
   3344 
   3345     if (&mTable == &other.mTable) {
   3346         for (size_t i=0; i<Res_MAXPACKAGE; i++) {
   3347             if (mPackages[i] != NULL) {
   3348                 free_package(mPackages[i]);
   3349             }
   3350             if (other.mPackages[i] != NULL) {
   3351                 mPackages[i] = copy_package(other.mPackages[i]);
   3352             } else {
   3353                 mPackages[i] = NULL;
   3354             }
   3355         }
   3356     } else {
   3357         // @todo: need to really implement this, not just copy
   3358         // the system package (which is still wrong because it isn't
   3359         // fixing up resource references).
   3360         for (size_t i=0; i<Res_MAXPACKAGE; i++) {
   3361             if (mPackages[i] != NULL) {
   3362                 free_package(mPackages[i]);
   3363             }
   3364             if (i == 0 && other.mPackages[i] != NULL) {
   3365                 mPackages[i] = copy_package(other.mPackages[i]);
   3366             } else {
   3367                 mPackages[i] = NULL;
   3368             }
   3369         }
   3370     }
   3371 
   3372     mTypeSpecFlags = other.mTypeSpecFlags;
   3373 
   3374     if (kDebugTableTheme) {
   3375         ALOGI("Final theme:");
   3376         dumpToLog();
   3377     }
   3378 
   3379     return NO_ERROR;
   3380 }
   3381 
   3382 status_t ResTable::Theme::clear()
   3383 {
   3384     if (kDebugTableTheme) {
   3385         ALOGI("Clearing theme %p...\n", this);
   3386         dumpToLog();
   3387     }
   3388 
   3389     for (size_t i = 0; i < Res_MAXPACKAGE; i++) {
   3390         if (mPackages[i] != NULL) {
   3391             free_package(mPackages[i]);
   3392             mPackages[i] = NULL;
   3393         }
   3394     }
   3395 
   3396     mTypeSpecFlags = 0;
   3397 
   3398     if (kDebugTableTheme) {
   3399         ALOGI("Final theme:");
   3400         dumpToLog();
   3401     }
   3402 
   3403     return NO_ERROR;
   3404 }
   3405 
   3406 ssize_t ResTable::Theme::getAttribute(uint32_t resID, Res_value* outValue,
   3407         uint32_t* outTypeSpecFlags) const
   3408 {
   3409     int cnt = 20;
   3410 
   3411     if (outTypeSpecFlags != NULL) *outTypeSpecFlags = 0;
   3412 
   3413     do {
   3414         const ssize_t p = mTable.getResourcePackageIndex(resID);
   3415         const uint32_t t = Res_GETTYPE(resID);
   3416         const uint32_t e = Res_GETENTRY(resID);
   3417 
   3418         if (kDebugTableTheme) {
   3419             ALOGI("Looking up attr 0x%08x in theme %p", resID, this);
   3420         }
   3421 
   3422         if (p >= 0) {
   3423             const package_info* const pi = mPackages[p];
   3424             if (kDebugTableTheme) {
   3425                 ALOGI("Found package: %p", pi);
   3426             }
   3427             if (pi != NULL) {
   3428                 if (kDebugTableTheme) {
   3429                     ALOGI("Desired type index is %zd in avail %zu", t, Res_MAXTYPE + 1);
   3430                 }
   3431                 if (t <= Res_MAXTYPE) {
   3432                     const type_info& ti = pi->types[t];
   3433                     if (kDebugTableTheme) {
   3434                         ALOGI("Desired entry index is %u in avail %zu", e, ti.numEntries);
   3435                     }
   3436                     if (e < ti.numEntries) {
   3437                         const theme_entry& te = ti.entries[e];
   3438                         if (outTypeSpecFlags != NULL) {
   3439                             *outTypeSpecFlags |= te.typeSpecFlags;
   3440                         }
   3441                         if (kDebugTableTheme) {
   3442                             ALOGI("Theme value: type=0x%x, data=0x%08x",
   3443                                     te.value.dataType, te.value.data);
   3444                         }
   3445                         const uint8_t type = te.value.dataType;
   3446                         if (type == Res_value::TYPE_ATTRIBUTE) {
   3447                             if (cnt > 0) {
   3448                                 cnt--;
   3449                                 resID = te.value.data;
   3450                                 continue;
   3451                             }
   3452                             ALOGW("Too many attribute references, stopped at: 0x%08x\n", resID);
   3453                             return BAD_INDEX;
   3454                         } else if (type != Res_value::TYPE_NULL) {
   3455                             *outValue = te.value;
   3456                             return te.stringBlock;
   3457                         }
   3458                         return BAD_INDEX;
   3459                     }
   3460                 }
   3461             }
   3462         }
   3463         break;
   3464 
   3465     } while (true);
   3466 
   3467     return BAD_INDEX;
   3468 }
   3469 
   3470 ssize_t ResTable::Theme::resolveAttributeReference(Res_value* inOutValue,
   3471         ssize_t blockIndex, uint32_t* outLastRef,
   3472         uint32_t* inoutTypeSpecFlags, ResTable_config* inoutConfig) const
   3473 {
   3474     //printf("Resolving type=0x%x\n", inOutValue->dataType);
   3475     if (inOutValue->dataType == Res_value::TYPE_ATTRIBUTE) {
   3476         uint32_t newTypeSpecFlags;
   3477         blockIndex = getAttribute(inOutValue->data, inOutValue, &newTypeSpecFlags);
   3478         if (kDebugTableTheme) {
   3479             ALOGI("Resolving attr reference: blockIndex=%d, type=0x%x, data=0x%x\n",
   3480                     (int)blockIndex, (int)inOutValue->dataType, inOutValue->data);
   3481         }
   3482         if (inoutTypeSpecFlags != NULL) *inoutTypeSpecFlags |= newTypeSpecFlags;
   3483         //printf("Retrieved attribute new type=0x%x\n", inOutValue->dataType);
   3484         if (blockIndex < 0) {
   3485             return blockIndex;
   3486         }
   3487     }
   3488     return mTable.resolveReference(inOutValue, blockIndex, outLastRef,
   3489             inoutTypeSpecFlags, inoutConfig);
   3490 }
   3491 
   3492 uint32_t ResTable::Theme::getChangingConfigurations() const
   3493 {
   3494     return mTypeSpecFlags;
   3495 }
   3496 
   3497 void ResTable::Theme::dumpToLog() const
   3498 {
   3499     ALOGI("Theme %p:\n", this);
   3500     for (size_t i=0; i<Res_MAXPACKAGE; i++) {
   3501         package_info* pi = mPackages[i];
   3502         if (pi == NULL) continue;
   3503 
   3504         ALOGI("  Package #0x%02x:\n", (int)(i + 1));
   3505         for (size_t j = 0; j <= Res_MAXTYPE; j++) {
   3506             type_info& ti = pi->types[j];
   3507             if (ti.numEntries == 0) continue;
   3508             ALOGI("    Type #0x%02x:\n", (int)(j + 1));
   3509             for (size_t k = 0; k < ti.numEntries; k++) {
   3510                 const theme_entry& te = ti.entries[k];
   3511                 if (te.value.dataType == Res_value::TYPE_NULL) continue;
   3512                 ALOGI("      0x%08x: t=0x%x, d=0x%08x (block=%d)\n",
   3513                      (int)Res_MAKEID(i, j, k),
   3514                      te.value.dataType, (int)te.value.data, (int)te.stringBlock);
   3515             }
   3516         }
   3517     }
   3518 }
   3519 
   3520 ResTable::ResTable()
   3521     : mError(NO_INIT), mNextPackageId(2)
   3522 {
   3523     memset(&mParams, 0, sizeof(mParams));
   3524     memset(mPackageMap, 0, sizeof(mPackageMap));
   3525     if (kDebugTableSuperNoisy) {
   3526         ALOGI("Creating ResTable %p\n", this);
   3527     }
   3528 }
   3529 
   3530 ResTable::ResTable(const void* data, size_t size, const int32_t cookie, bool copyData)
   3531     : mError(NO_INIT), mNextPackageId(2)
   3532 {
   3533     memset(&mParams, 0, sizeof(mParams));
   3534     memset(mPackageMap, 0, sizeof(mPackageMap));
   3535     addInternal(data, size, NULL, 0, cookie, copyData);
   3536     LOG_FATAL_IF(mError != NO_ERROR, "Error parsing resource table");
   3537     if (kDebugTableSuperNoisy) {
   3538         ALOGI("Creating ResTable %p\n", this);
   3539     }
   3540 }
   3541 
   3542 ResTable::~ResTable()
   3543 {
   3544     if (kDebugTableSuperNoisy) {
   3545         ALOGI("Destroying ResTable in %p\n", this);
   3546     }
   3547     uninit();
   3548 }
   3549 
   3550 inline ssize_t ResTable::getResourcePackageIndex(uint32_t resID) const
   3551 {
   3552     return ((ssize_t)mPackageMap[Res_GETPACKAGE(resID)+1])-1;
   3553 }
   3554 
   3555 status_t ResTable::add(const void* data, size_t size, const int32_t cookie, bool copyData) {
   3556     return addInternal(data, size, NULL, 0, cookie, copyData);
   3557 }
   3558 
   3559 status_t ResTable::add(const void* data, size_t size, const void* idmapData, size_t idmapDataSize,
   3560         const int32_t cookie, bool copyData) {
   3561     return addInternal(data, size, idmapData, idmapDataSize, cookie, copyData);
   3562 }
   3563 
   3564 status_t ResTable::add(Asset* asset, const int32_t cookie, bool copyData) {
   3565     const void* data = asset->getBuffer(true);
   3566     if (data == NULL) {
   3567         ALOGW("Unable to get buffer of resource asset file");
   3568         return UNKNOWN_ERROR;
   3569     }
   3570 
   3571     return addInternal(data, static_cast<size_t>(asset->getLength()), NULL, 0, cookie, copyData);
   3572 }
   3573 
   3574 status_t ResTable::add(Asset* asset, Asset* idmapAsset, const int32_t cookie, bool copyData) {
   3575     const void* data = asset->getBuffer(true);
   3576     if (data == NULL) {
   3577         ALOGW("Unable to get buffer of resource asset file");
   3578         return UNKNOWN_ERROR;
   3579     }
   3580 
   3581     size_t idmapSize = 0;
   3582     const void* idmapData = NULL;
   3583     if (idmapAsset != NULL) {
   3584         idmapData = idmapAsset->getBuffer(true);
   3585         if (idmapData == NULL) {
   3586             ALOGW("Unable to get buffer of idmap asset file");
   3587             return UNKNOWN_ERROR;
   3588         }
   3589         idmapSize = static_cast<size_t>(idmapAsset->getLength());
   3590     }
   3591 
   3592     return addInternal(data, static_cast<size_t>(asset->getLength()),
   3593             idmapData, idmapSize, cookie, copyData);
   3594 }
   3595 
   3596 status_t ResTable::add(ResTable* src)
   3597 {
   3598     mError = src->mError;
   3599 
   3600     for (size_t i=0; i<src->mHeaders.size(); i++) {
   3601         mHeaders.add(src->mHeaders[i]);
   3602     }
   3603 
   3604     for (size_t i=0; i<src->mPackageGroups.size(); i++) {
   3605         PackageGroup* srcPg = src->mPackageGroups[i];
   3606         PackageGroup* pg = new PackageGroup(this, srcPg->name, srcPg->id);
   3607         for (size_t j=0; j<srcPg->packages.size(); j++) {
   3608             pg->packages.add(srcPg->packages[j]);
   3609         }
   3610 
   3611         for (size_t j = 0; j < srcPg->types.size(); j++) {
   3612             if (srcPg->types[j].isEmpty()) {
   3613                 continue;
   3614             }
   3615 
   3616             TypeList& typeList = pg->types.editItemAt(j);
   3617             typeList.appendVector(srcPg->types[j]);
   3618         }
   3619         pg->dynamicRefTable.addMappings(srcPg->dynamicRefTable);
   3620         pg->largestTypeId = max(pg->largestTypeId, srcPg->largestTypeId);
   3621         mPackageGroups.add(pg);
   3622     }
   3623 
   3624     memcpy(mPackageMap, src->mPackageMap, sizeof(mPackageMap));
   3625 
   3626     return mError;
   3627 }
   3628 
   3629 status_t ResTable::addEmpty(const int32_t cookie) {
   3630     Header* header = new Header(this);
   3631     header->index = mHeaders.size();
   3632     header->cookie = cookie;
   3633     header->values.setToEmpty();
   3634     header->ownedData = calloc(1, sizeof(ResTable_header));
   3635 
   3636     ResTable_header* resHeader = (ResTable_header*) header->ownedData;
   3637     resHeader->header.type = RES_TABLE_TYPE;
   3638     resHeader->header.headerSize = sizeof(ResTable_header);
   3639     resHeader->header.size = sizeof(ResTable_header);
   3640 
   3641     header->header = (const ResTable_header*) resHeader;
   3642     mHeaders.add(header);
   3643     return (mError=NO_ERROR);
   3644 }
   3645 
   3646 status_t ResTable::addInternal(const void* data, size_t dataSize, const void* idmapData, size_t idmapDataSize,
   3647         const int32_t cookie, bool copyData)
   3648 {
   3649     if (!data) {
   3650         return NO_ERROR;
   3651     }
   3652 
   3653     if (dataSize < sizeof(ResTable_header)) {
   3654         ALOGE("Invalid data. Size(%d) is smaller than a ResTable_header(%d).",
   3655                 (int) dataSize, (int) sizeof(ResTable_header));
   3656         return UNKNOWN_ERROR;
   3657     }
   3658 
   3659     Header* header = new Header(this);
   3660     header->index = mHeaders.size();
   3661     header->cookie = cookie;
   3662     if (idmapData != NULL) {
   3663         header->resourceIDMap = (uint32_t*) malloc(idmapDataSize);
   3664         if (header->resourceIDMap == NULL) {
   3665             delete header;
   3666             return (mError = NO_MEMORY);
   3667         }
   3668         memcpy(header->resourceIDMap, idmapData, idmapDataSize);
   3669         header->resourceIDMapSize = idmapDataSize;
   3670     }
   3671     mHeaders.add(header);
   3672 
   3673     const bool notDeviceEndian = htods(0xf0) != 0xf0;
   3674 
   3675     if (kDebugLoadTableNoisy) {
   3676         ALOGV("Adding resources to ResTable: data=%p, size=%zu, cookie=%d, copy=%d "
   3677                 "idmap=%p\n", data, dataSize, cookie, copyData, idmapData);
   3678     }
   3679 
   3680     if (copyData || notDeviceEndian) {
   3681         header->ownedData = malloc(dataSize);
   3682         if (header->ownedData == NULL) {
   3683             return (mError=NO_MEMORY);
   3684         }
   3685         memcpy(header->ownedData, data, dataSize);
   3686         data = header->ownedData;
   3687     }
   3688 
   3689     header->header = (const ResTable_header*)data;
   3690     header->size = dtohl(header->header->header.size);
   3691     if (kDebugLoadTableSuperNoisy) {
   3692         ALOGI("Got size %zu, again size 0x%x, raw size 0x%x\n", header->size,
   3693                 dtohl(header->header->header.size), header->header->header.size);
   3694     }
   3695     if (kDebugLoadTableNoisy) {
   3696         ALOGV("Loading ResTable @%p:\n", header->header);
   3697     }
   3698     if (dtohs(header->header->header.headerSize) > header->size
   3699             || header->size > dataSize) {
   3700         ALOGW("Bad resource table: header size 0x%x or total size 0x%x is larger than data size 0x%x\n",
   3701              (int)dtohs(header->header->header.headerSize),
   3702              (int)header->size, (int)dataSize);
   3703         return (mError=BAD_TYPE);
   3704     }
   3705     if (((dtohs(header->header->header.headerSize)|header->size)&0x3) != 0) {
   3706         ALOGW("Bad resource table: header size 0x%x or total size 0x%x is not on an integer boundary\n",
   3707              (int)dtohs(header->header->header.headerSize),
   3708              (int)header->size);
   3709         return (mError=BAD_TYPE);
   3710     }
   3711     header->dataEnd = ((const uint8_t*)header->header) + header->size;
   3712 
   3713     // Iterate through all chunks.
   3714     size_t curPackage = 0;
   3715 
   3716     const ResChunk_header* chunk =
   3717         (const ResChunk_header*)(((const uint8_t*)header->header)
   3718                                  + dtohs(header->header->header.headerSize));
   3719     while (((const uint8_t*)chunk) <= (header->dataEnd-sizeof(ResChunk_header)) &&
   3720            ((const uint8_t*)chunk) <= (header->dataEnd-dtohl(chunk->size))) {
   3721         status_t err = validate_chunk(chunk, sizeof(ResChunk_header), header->dataEnd, "ResTable");
   3722         if (err != NO_ERROR) {
   3723             return (mError=err);
   3724         }
   3725         if (kDebugTableNoisy) {
   3726             ALOGV("Chunk: type=0x%x, headerSize=0x%x, size=0x%x, pos=%p\n",
   3727                     dtohs(chunk->type), dtohs(chunk->headerSize), dtohl(chunk->size),
   3728                     (void*)(((const uint8_t*)chunk) - ((const uint8_t*)header->header)));
   3729         }
   3730         const size_t csize = dtohl(chunk->size);
   3731         const uint16_t ctype = dtohs(chunk->type);
   3732         if (ctype == RES_STRING_POOL_TYPE) {
   3733             if (header->values.getError() != NO_ERROR) {
   3734                 // Only use the first string chunk; ignore any others that
   3735                 // may appear.
   3736                 status_t err = header->values.setTo(chunk, csize);
   3737                 if (err != NO_ERROR) {
   3738                     return (mError=err);
   3739                 }
   3740             } else {
   3741                 ALOGW("Multiple string chunks found in resource table.");
   3742             }
   3743         } else if (ctype == RES_TABLE_PACKAGE_TYPE) {
   3744             if (curPackage >= dtohl(header->header->packageCount)) {
   3745                 ALOGW("More package chunks were found than the %d declared in the header.",
   3746                      dtohl(header->header->packageCount));
   3747                 return (mError=BAD_TYPE);
   3748             }
   3749 
   3750             if (parsePackage((ResTable_package*)chunk, header) != NO_ERROR) {
   3751                 return mError;
   3752             }
   3753             curPackage++;
   3754         } else {
   3755             ALOGW("Unknown chunk type 0x%x in table at %p.\n",
   3756                  ctype,
   3757                  (void*)(((const uint8_t*)chunk) - ((const uint8_t*)header->header)));
   3758         }
   3759         chunk = (const ResChunk_header*)
   3760             (((const uint8_t*)chunk) + csize);
   3761     }
   3762 
   3763     if (curPackage < dtohl(header->header->packageCount)) {
   3764         ALOGW("Fewer package chunks (%d) were found than the %d declared in the header.",
   3765              (int)curPackage, dtohl(header->header->packageCount));
   3766         return (mError=BAD_TYPE);
   3767     }
   3768     mError = header->values.getError();
   3769     if (mError != NO_ERROR) {
   3770         ALOGW("No string values found in resource table!");
   3771     }
   3772 
   3773     if (kDebugTableNoisy) {
   3774         ALOGV("Returning from add with mError=%d\n", mError);
   3775     }
   3776     return mError;
   3777 }
   3778 
   3779 status_t ResTable::getError() const
   3780 {
   3781     return mError;
   3782 }
   3783 
   3784 void ResTable::uninit()
   3785 {
   3786     mError = NO_INIT;
   3787     size_t N = mPackageGroups.size();
   3788     for (size_t i=0; i<N; i++) {
   3789         PackageGroup* g = mPackageGroups[i];
   3790         delete g;
   3791     }
   3792     N = mHeaders.size();
   3793     for (size_t i=0; i<N; i++) {
   3794         Header* header = mHeaders[i];
   3795         if (header->owner == this) {
   3796             if (header->ownedData) {
   3797                 free(header->ownedData);
   3798             }
   3799             delete header;
   3800         }
   3801     }
   3802 
   3803     mPackageGroups.clear();
   3804     mHeaders.clear();
   3805 }
   3806 
   3807 bool ResTable::getResourceName(uint32_t resID, bool allowUtf8, resource_name* outName) const
   3808 {
   3809     if (mError != NO_ERROR) {
   3810         return false;
   3811     }
   3812 
   3813     const ssize_t p = getResourcePackageIndex(resID);
   3814     const int t = Res_GETTYPE(resID);
   3815     const int e = Res_GETENTRY(resID);
   3816 
   3817     if (p < 0) {
   3818         if (Res_GETPACKAGE(resID)+1 == 0) {
   3819             ALOGW("No package identifier when getting name for resource number 0x%08x", resID);
   3820         } else {
   3821             ALOGW("No known package when getting name for resource number 0x%08x", resID);
   3822         }
   3823         return false;
   3824     }
   3825     if (t < 0) {
   3826         ALOGW("No type identifier when getting name for resource number 0x%08x", resID);
   3827         return false;
   3828     }
   3829 
   3830     const PackageGroup* const grp = mPackageGroups[p];
   3831     if (grp == NULL) {
   3832         ALOGW("Bad identifier when getting name for resource number 0x%08x", resID);
   3833         return false;
   3834     }
   3835 
   3836     Entry entry;
   3837     status_t err = getEntry(grp, t, e, NULL, &entry);
   3838     if (err != NO_ERROR) {
   3839         return false;
   3840     }
   3841 
   3842     outName->package = grp->name.string();
   3843     outName->packageLen = grp->name.size();
   3844     if (allowUtf8) {
   3845         outName->type8 = entry.typeStr.string8(&outName->typeLen);
   3846         outName->name8 = entry.keyStr.string8(&outName->nameLen);
   3847     } else {
   3848         outName->type8 = NULL;
   3849         outName->name8 = NULL;
   3850     }
   3851     if (outName->type8 == NULL) {
   3852         outName->type = entry.typeStr.string16(&outName->typeLen);
   3853         // If we have a bad index for some reason, we should abort.
   3854         if (outName->type == NULL) {
   3855             return false;
   3856         }
   3857     }
   3858     if (outName->name8 == NULL) {
   3859         outName->name = entry.keyStr.string16(&outName->nameLen);
   3860         // If we have a bad index for some reason, we should abort.
   3861         if (outName->name == NULL) {
   3862             return false;
   3863         }
   3864     }
   3865 
   3866     return true;
   3867 }
   3868 
   3869 ssize_t ResTable::getResource(uint32_t resID, Res_value* outValue, bool mayBeBag, uint16_t density,
   3870         uint32_t* outSpecFlags, ResTable_config* outConfig) const
   3871 {
   3872     if (mError != NO_ERROR) {
   3873         return mError;
   3874     }
   3875 
   3876     const ssize_t p = getResourcePackageIndex(resID);
   3877     const int t = Res_GETTYPE(resID);
   3878     const int e = Res_GETENTRY(resID);
   3879 
   3880     if (p < 0) {
   3881         if (Res_GETPACKAGE(resID)+1 == 0) {
   3882             ALOGW("No package identifier when getting value for resource number 0x%08x", resID);
   3883         } else {
   3884             ALOGW("No known package when getting value for resource number 0x%08x", resID);
   3885         }
   3886         return BAD_INDEX;
   3887     }
   3888     if (t < 0) {
   3889         ALOGW("No type identifier when getting value for resource number 0x%08x", resID);
   3890         return BAD_INDEX;
   3891     }
   3892 
   3893     const PackageGroup* const grp = mPackageGroups[p];
   3894     if (grp == NULL) {
   3895         ALOGW("Bad identifier when getting value for resource number 0x%08x", resID);
   3896         return BAD_INDEX;
   3897     }
   3898 
   3899     // Allow overriding density
   3900     ResTable_config desiredConfig = mParams;
   3901     if (density > 0) {
   3902         desiredConfig.density = density;
   3903     }
   3904 
   3905     Entry entry;
   3906     status_t err = getEntry(grp, t, e, &desiredConfig, &entry);
   3907     if (err != NO_ERROR) {
   3908         // Only log the failure when we're not running on the host as
   3909         // part of a tool. The caller will do its own logging.
   3910 #ifndef STATIC_ANDROIDFW_FOR_TOOLS
   3911         ALOGW("Failure getting entry for 0x%08x (t=%d e=%d) (error %d)\n",
   3912                 resID, t, e, err);
   3913 #endif
   3914         return err;
   3915     }
   3916 
   3917     if ((dtohs(entry.entry->flags) & ResTable_entry::FLAG_COMPLEX) != 0) {
   3918         if (!mayBeBag) {
   3919             ALOGW("Requesting resource 0x%08x failed because it is complex\n", resID);
   3920         }
   3921         return BAD_VALUE;
   3922     }
   3923 
   3924     const Res_value* value = reinterpret_cast<const Res_value*>(
   3925             reinterpret_cast<const uint8_t*>(entry.entry) + entry.entry->size);
   3926 
   3927     outValue->size = dtohs(value->size);
   3928     outValue->res0 = value->res0;
   3929     outValue->dataType = value->dataType;
   3930     outValue->data = dtohl(value->data);
   3931 
   3932     // The reference may be pointing to a resource in a shared library. These
   3933     // references have build-time generated package IDs. These ids may not match
   3934     // the actual package IDs of the corresponding packages in this ResTable.
   3935     // We need to fix the package ID based on a mapping.
   3936     if (grp->dynamicRefTable.lookupResourceValue(outValue) != NO_ERROR) {
   3937         ALOGW("Failed to resolve referenced package: 0x%08x", outValue->data);
   3938         return BAD_VALUE;
   3939     }
   3940 
   3941     if (kDebugTableNoisy) {
   3942         size_t len;
   3943         printf("Found value: pkg=%zu, type=%d, str=%s, int=%d\n",
   3944                 entry.package->header->index,
   3945                 outValue->dataType,
   3946                 outValue->dataType == Res_value::TYPE_STRING ?
   3947                     String8(entry.package->header->values.stringAt(outValue->data, &len)).string() :
   3948                     "",
   3949                 outValue->data);
   3950     }
   3951 
   3952     if (outSpecFlags != NULL) {
   3953         *outSpecFlags = entry.specFlags;
   3954     }
   3955 
   3956     if (outConfig != NULL) {
   3957         *outConfig = entry.config;
   3958     }
   3959 
   3960     return entry.package->header->index;
   3961 }
   3962 
   3963 ssize_t ResTable::resolveReference(Res_value* value, ssize_t blockIndex,
   3964         uint32_t* outLastRef, uint32_t* inoutTypeSpecFlags,
   3965         ResTable_config* outConfig) const
   3966 {
   3967     int count=0;
   3968     while (blockIndex >= 0 && value->dataType == Res_value::TYPE_REFERENCE
   3969             && value->data != 0 && count < 20) {
   3970         if (outLastRef) *outLastRef = value->data;
   3971         uint32_t newFlags = 0;
   3972         const ssize_t newIndex = getResource(value->data, value, true, 0, &newFlags,
   3973                 outConfig);
   3974         if (newIndex == BAD_INDEX) {
   3975             return BAD_INDEX;
   3976         }
   3977         if (kDebugTableTheme) {
   3978             ALOGI("Resolving reference 0x%x: newIndex=%d, type=0x%x, data=0x%x\n",
   3979                     value->data, (int)newIndex, (int)value->dataType, value->data);
   3980         }
   3981         //printf("Getting reference 0x%08x: newIndex=%d\n", value->data, newIndex);
   3982         if (inoutTypeSpecFlags != NULL) *inoutTypeSpecFlags |= newFlags;
   3983         if (newIndex < 0) {
   3984             // This can fail if the resource being referenced is a style...
   3985             // in this case, just return the reference, and expect the
   3986             // caller to deal with.
   3987             return blockIndex;
   3988         }
   3989         blockIndex = newIndex;
   3990         count++;
   3991     }
   3992     return blockIndex;
   3993 }
   3994 
   3995 const char16_t* ResTable::valueToString(
   3996     const Res_value* value, size_t stringBlock,
   3997     char16_t /*tmpBuffer*/ [TMP_BUFFER_SIZE], size_t* outLen) const
   3998 {
   3999     if (!value) {
   4000         return NULL;
   4001     }
   4002     if (value->dataType == value->TYPE_STRING) {
   4003         return getTableStringBlock(stringBlock)->stringAt(value->data, outLen);
   4004     }
   4005     // XXX do int to string conversions.
   4006     return NULL;
   4007 }
   4008 
   4009 ssize_t ResTable::lockBag(uint32_t resID, const bag_entry** outBag) const
   4010 {
   4011     mLock.lock();
   4012     ssize_t err = getBagLocked(resID, outBag);
   4013     if (err < NO_ERROR) {
   4014         //printf("*** get failed!  unlocking\n");
   4015         mLock.unlock();
   4016     }
   4017     return err;
   4018 }
   4019 
   4020 void ResTable::unlockBag(const bag_entry* /*bag*/) const
   4021 {
   4022     //printf("<<< unlockBag %p\n", this);
   4023     mLock.unlock();
   4024 }
   4025 
   4026 void ResTable::lock() const
   4027 {
   4028     mLock.lock();
   4029 }
   4030 
   4031 void ResTable::unlock() const
   4032 {
   4033     mLock.unlock();
   4034 }
   4035 
   4036 ssize_t ResTable::getBagLocked(uint32_t resID, const bag_entry** outBag,
   4037         uint32_t* outTypeSpecFlags) const
   4038 {
   4039     if (mError != NO_ERROR) {
   4040         return mError;
   4041     }
   4042 
   4043     const ssize_t p = getResourcePackageIndex(resID);
   4044     const int t = Res_GETTYPE(resID);
   4045     const int e = Res_GETENTRY(resID);
   4046 
   4047     if (p < 0) {
   4048         ALOGW("Invalid package identifier when getting bag for resource number 0x%08x", resID);
   4049         return BAD_INDEX;
   4050     }
   4051     if (t < 0) {
   4052         ALOGW("No type identifier when getting bag for resource number 0x%08x", resID);
   4053         return BAD_INDEX;
   4054     }
   4055 
   4056     //printf("Get bag: id=0x%08x, p=%d, t=%d\n", resID, p, t);
   4057     PackageGroup* const grp = mPackageGroups[p];
   4058     if (grp == NULL) {
   4059         ALOGW("Bad identifier when getting bag for resource number 0x%08x", resID);
   4060         return BAD_INDEX;
   4061     }
   4062 
   4063     const TypeList& typeConfigs = grp->types[t];
   4064     if (typeConfigs.isEmpty()) {
   4065         ALOGW("Type identifier 0x%x does not exist.", t+1);
   4066         return BAD_INDEX;
   4067     }
   4068 
   4069     const size_t NENTRY = typeConfigs[0]->entryCount;
   4070     if (e >= (int)NENTRY) {
   4071         ALOGW("Entry identifier 0x%x is larger than entry count 0x%x",
   4072              e, (int)typeConfigs[0]->entryCount);
   4073         return BAD_INDEX;
   4074     }
   4075 
   4076     // First see if we've already computed this bag...
   4077     if (grp->bags) {
   4078         bag_set** typeSet = grp->bags->get(t);
   4079         if (typeSet) {
   4080             bag_set* set = typeSet[e];
   4081             if (set) {
   4082                 if (set != (bag_set*)0xFFFFFFFF) {
   4083                     if (outTypeSpecFlags != NULL) {
   4084                         *outTypeSpecFlags = set->typeSpecFlags;
   4085                     }
   4086                     *outBag = (bag_entry*)(set+1);
   4087                     if (kDebugTableSuperNoisy) {
   4088                         ALOGI("Found existing bag for: 0x%x\n", resID);
   4089                     }
   4090                     return set->numAttrs;
   4091                 }
   4092                 ALOGW("Attempt to retrieve bag 0x%08x which is invalid or in a cycle.",
   4093                      resID);
   4094                 return BAD_INDEX;
   4095             }
   4096         }
   4097     }
   4098 
   4099     // Bag not found, we need to compute it!
   4100     if (!grp->bags) {
   4101         grp->bags = new ByteBucketArray<bag_set**>();
   4102         if (!grp->bags) return NO_MEMORY;
   4103     }
   4104 
   4105     bag_set** typeSet = grp->bags->get(t);
   4106     if (!typeSet) {
   4107         typeSet = (bag_set**)calloc(NENTRY, sizeof(bag_set*));
   4108         if (!typeSet) return NO_MEMORY;
   4109         grp->bags->set(t, typeSet);
   4110     }
   4111 
   4112     // Mark that we are currently working on this one.
   4113     typeSet[e] = (bag_set*)0xFFFFFFFF;
   4114 
   4115     if (kDebugTableNoisy) {
   4116         ALOGI("Building bag: %x\n", resID);
   4117     }
   4118 
   4119     // Now collect all bag attributes
   4120     Entry entry;
   4121     status_t err = getEntry(grp, t, e, &mParams, &entry);
   4122     if (err != NO_ERROR) {
   4123         return err;
   4124     }
   4125 
   4126     const uint16_t entrySize = dtohs(entry.entry->size);
   4127     const uint32_t parent = entrySize >= sizeof(ResTable_map_entry)
   4128         ? dtohl(((const ResTable_map_entry*)entry.entry)->parent.ident) : 0;
   4129     const uint32_t count = entrySize >= sizeof(ResTable_map_entry)
   4130         ? dtohl(((const ResTable_map_entry*)entry.entry)->count) : 0;
   4131 
   4132     size_t N = count;
   4133 
   4134     if (kDebugTableNoisy) {
   4135         ALOGI("Found map: size=%x parent=%x count=%d\n", entrySize, parent, count);
   4136 
   4137     // If this map inherits from another, we need to start
   4138     // with its parent's values.  Otherwise start out empty.
   4139         ALOGI("Creating new bag, entrySize=0x%08x, parent=0x%08x\n", entrySize, parent);
   4140     }
   4141 
   4142     // This is what we are building.
   4143     bag_set* set = NULL;
   4144 
   4145     if (parent) {
   4146         uint32_t resolvedParent = parent;
   4147 
   4148         // Bags encode a parent reference without using the standard
   4149         // Res_value structure. That means we must always try to
   4150         // resolve a parent reference in case it is actually a
   4151         // TYPE_DYNAMIC_REFERENCE.
   4152         status_t err = grp->dynamicRefTable.lookupResourceId(&resolvedParent);
   4153         if (err != NO_ERROR) {
   4154             ALOGE("Failed resolving bag parent id 0x%08x", parent);
   4155             return UNKNOWN_ERROR;
   4156         }
   4157 
   4158         const bag_entry* parentBag;
   4159         uint32_t parentTypeSpecFlags = 0;
   4160         const ssize_t NP = getBagLocked(resolvedParent, &parentBag, &parentTypeSpecFlags);
   4161         const size_t NT = ((NP >= 0) ? NP : 0) + N;
   4162         set = (bag_set*)malloc(sizeof(bag_set)+sizeof(bag_entry)*NT);
   4163         if (set == NULL) {
   4164             return NO_MEMORY;
   4165         }
   4166         if (NP > 0) {
   4167             memcpy(set+1, parentBag, NP*sizeof(bag_entry));
   4168             set->numAttrs = NP;
   4169             if (kDebugTableNoisy) {
   4170                 ALOGI("Initialized new bag with %zd inherited attributes.\n", NP);
   4171             }
   4172         } else {
   4173             if (kDebugTableNoisy) {
   4174                 ALOGI("Initialized new bag with no inherited attributes.\n");
   4175             }
   4176             set->numAttrs = 0;
   4177         }
   4178         set->availAttrs = NT;
   4179         set->typeSpecFlags = parentTypeSpecFlags;
   4180     } else {
   4181         set = (bag_set*)malloc(sizeof(bag_set)+sizeof(bag_entry)*N);
   4182         if (set == NULL) {
   4183             return NO_MEMORY;
   4184         }
   4185         set->numAttrs = 0;
   4186         set->availAttrs = N;
   4187         set->typeSpecFlags = 0;
   4188     }
   4189 
   4190     set->typeSpecFlags |= entry.specFlags;
   4191 
   4192     // Now merge in the new attributes...
   4193     size_t curOff = (reinterpret_cast<uintptr_t>(entry.entry) - reinterpret_cast<uintptr_t>(entry.type))
   4194         + dtohs(entry.entry->size);
   4195     const ResTable_map* map;
   4196     bag_entry* entries = (bag_entry*)(set+1);
   4197     size_t curEntry = 0;
   4198     uint32_t pos = 0;
   4199     if (kDebugTableNoisy) {
   4200         ALOGI("Starting with set %p, entries=%p, avail=%zu\n", set, entries, set->availAttrs);
   4201     }
   4202     while (pos < count) {
   4203         if (kDebugTableNoisy) {
   4204             ALOGI("Now at %p\n", (void*)curOff);
   4205         }
   4206 
   4207         if (curOff > (dtohl(entry.type->header.size)-sizeof(ResTable_map))) {
   4208             ALOGW("ResTable_map at %d is beyond type chunk data %d",
   4209                  (int)curOff, dtohl(entry.type->header.size));
   4210             return BAD_TYPE;
   4211         }
   4212         map = (const ResTable_map*)(((const uint8_t*)entry.type) + curOff);
   4213         N++;
   4214 
   4215         uint32_t newName = htodl(map->name.ident);
   4216         if (!Res_INTERNALID(newName)) {
   4217             // Attributes don't have a resource id as the name. They specify
   4218             // other data, which would be wrong to change via a lookup.
   4219             if (grp->dynamicRefTable.lookupResourceId(&newName) != NO_ERROR) {
   4220                 ALOGE("Failed resolving ResTable_map name at %d with ident 0x%08x",
   4221                         (int) curOff, (int) newName);
   4222                 return UNKNOWN_ERROR;
   4223             }
   4224         }
   4225 
   4226         bool isInside;
   4227         uint32_t oldName = 0;
   4228         while ((isInside=(curEntry < set->numAttrs))
   4229                 && (oldName=entries[curEntry].map.name.ident) < newName) {
   4230             if (kDebugTableNoisy) {
   4231                 ALOGI("#%zu: Keeping existing attribute: 0x%08x\n",
   4232                         curEntry, entries[curEntry].map.name.ident);
   4233             }
   4234             curEntry++;
   4235         }
   4236 
   4237         if ((!isInside) || oldName != newName) {
   4238             // This is a new attribute...  figure out what to do with it.
   4239             if (set->numAttrs >= set->availAttrs) {
   4240                 // Need to alloc more memory...
   4241                 const size_t newAvail = set->availAttrs+N;
   4242                 set = (bag_set*)realloc(set,
   4243                                         sizeof(bag_set)
   4244                                         + sizeof(bag_entry)*newAvail);
   4245                 if (set == NULL) {
   4246                     return NO_MEMORY;
   4247                 }
   4248                 set->availAttrs = newAvail;
   4249                 entries = (bag_entry*)(set+1);
   4250                 if (kDebugTableNoisy) {
   4251                     ALOGI("Reallocated set %p, entries=%p, avail=%zu\n",
   4252                             set, entries, set->availAttrs);
   4253                 }
   4254             }
   4255             if (isInside) {
   4256                 // Going in the middle, need to make space.
   4257                 memmove(entries+curEntry+1, entries+curEntry,
   4258                         sizeof(bag_entry)*(set->numAttrs-curEntry));
   4259                 set->numAttrs++;
   4260             }
   4261             if (kDebugTableNoisy) {
   4262                 ALOGI("#%zu: Inserting new attribute: 0x%08x\n", curEntry, newName);
   4263             }
   4264         } else {
   4265             if (kDebugTableNoisy) {
   4266                 ALOGI("#%zu: Replacing existing attribute: 0x%08x\n", curEntry, oldName);
   4267             }
   4268         }
   4269 
   4270         bag_entry* cur = entries+curEntry;
   4271 
   4272         cur->stringBlock = entry.package->header->index;
   4273         cur->map.name.ident = newName;
   4274         cur->map.value.copyFrom_dtoh(map->value);
   4275         status_t err = grp->dynamicRefTable.lookupResourceValue(&cur->map.value);
   4276         if (err != NO_ERROR) {
   4277             ALOGE("Reference item(0x%08x) in bag could not be resolved.", cur->map.value.data);
   4278             return UNKNOWN_ERROR;
   4279         }
   4280 
   4281         if (kDebugTableNoisy) {
   4282             ALOGI("Setting entry #%zu %p: block=%zd, name=0x%08d, type=%d, data=0x%08x\n",
   4283                     curEntry, cur, cur->stringBlock, cur->map.name.ident,
   4284                     cur->map.value.dataType, cur->map.value.data);
   4285         }
   4286 
   4287         // On to the next!
   4288         curEntry++;
   4289         pos++;
   4290         const size_t size = dtohs(map->value.size);
   4291         curOff += size + sizeof(*map)-sizeof(map->value);
   4292     };
   4293 
   4294     if (curEntry > set->numAttrs) {
   4295         set->numAttrs = curEntry;
   4296     }
   4297 
   4298     // And this is it...
   4299     typeSet[e] = set;
   4300     if (set) {
   4301         if (outTypeSpecFlags != NULL) {
   4302             *outTypeSpecFlags = set->typeSpecFlags;
   4303         }
   4304         *outBag = (bag_entry*)(set+1);
   4305         if (kDebugTableNoisy) {
   4306             ALOGI("Returning %zu attrs\n", set->numAttrs);
   4307         }
   4308         return set->numAttrs;
   4309     }
   4310     return BAD_INDEX;
   4311 }
   4312 
   4313 void ResTable::setParameters(const ResTable_config* params)
   4314 {
   4315     mLock.lock();
   4316     if (kDebugTableGetEntry) {
   4317         ALOGI("Setting parameters: %s\n", params->toString().string());
   4318     }
   4319     mParams = *params;
   4320     for (size_t i=0; i<mPackageGroups.size(); i++) {
   4321         if (kDebugTableNoisy) {
   4322             ALOGI("CLEARING BAGS FOR GROUP %zu!", i);
   4323         }
   4324         mPackageGroups[i]->clearBagCache();
   4325     }
   4326     mLock.unlock();
   4327 }
   4328 
   4329 void ResTable::getParameters(ResTable_config* params) const
   4330 {
   4331     mLock.lock();
   4332     *params = mParams;
   4333     mLock.unlock();
   4334 }
   4335 
   4336 struct id_name_map {
   4337     uint32_t id;
   4338     size_t len;
   4339     char16_t name[6];
   4340 };
   4341 
   4342 const static id_name_map ID_NAMES[] = {
   4343     { ResTable_map::ATTR_TYPE,  5, { '^', 't', 'y', 'p', 'e' } },
   4344     { ResTable_map::ATTR_L10N,  5, { '^', 'l', '1', '0', 'n' } },
   4345     { ResTable_map::ATTR_MIN,   4, { '^', 'm', 'i', 'n' } },
   4346     { ResTable_map::ATTR_MAX,   4, { '^', 'm', 'a', 'x' } },
   4347     { ResTable_map::ATTR_OTHER, 6, { '^', 'o', 't', 'h', 'e', 'r' } },
   4348     { ResTable_map::ATTR_ZERO,  5, { '^', 'z', 'e', 'r', 'o' } },
   4349     { ResTable_map::ATTR_ONE,   4, { '^', 'o', 'n', 'e' } },
   4350     { ResTable_map::ATTR_TWO,   4, { '^', 't', 'w', 'o' } },
   4351     { ResTable_map::ATTR_FEW,   4, { '^', 'f', 'e', 'w' } },
   4352     { ResTable_map::ATTR_MANY,  5, { '^', 'm', 'a', 'n', 'y' } },
   4353 };
   4354 
   4355 uint32_t ResTable::identifierForName(const char16_t* name, size_t nameLen,
   4356                                      const char16_t* type, size_t typeLen,
   4357                                      const char16_t* package,
   4358                                      size_t packageLen,
   4359                                      uint32_t* outTypeSpecFlags) const
   4360 {
   4361     if (kDebugTableSuperNoisy) {
   4362         printf("Identifier for name: error=%d\n", mError);
   4363     }
   4364 
   4365     // Check for internal resource identifier as the very first thing, so
   4366     // that we will always find them even when there are no resources.
   4367     if (name[0] == '^') {
   4368         const int N = (sizeof(ID_NAMES)/sizeof(ID_NAMES[0]));
   4369         size_t len;
   4370         for (int i=0; i<N; i++) {
   4371             const id_name_map* m = ID_NAMES + i;
   4372             len = m->len;
   4373             if (len != nameLen) {
   4374                 continue;
   4375             }
   4376             for (size_t j=1; j<len; j++) {
   4377                 if (m->name[j] != name[j]) {
   4378                     goto nope;
   4379                 }
   4380             }
   4381             if (outTypeSpecFlags) {
   4382                 *outTypeSpecFlags = ResTable_typeSpec::SPEC_PUBLIC;
   4383             }
   4384             return m->id;
   4385 nope:
   4386             ;
   4387         }
   4388         if (nameLen > 7) {
   4389             if (name[1] == 'i' && name[2] == 'n'
   4390                 && name[3] == 'd' && name[4] == 'e' && name[5] == 'x'
   4391                 && name[6] == '_') {
   4392                 int index = atoi(String8(name + 7, nameLen - 7).string());
   4393                 if (Res_CHECKID(index)) {
   4394                     ALOGW("Array resource index: %d is too large.",
   4395                          index);
   4396                     return 0;
   4397                 }
   4398                 if (outTypeSpecFlags) {
   4399                     *outTypeSpecFlags = ResTable_typeSpec::SPEC_PUBLIC;
   4400                 }
   4401                 return  Res_MAKEARRAY(index);
   4402             }
   4403         }
   4404         return 0;
   4405     }
   4406 
   4407     if (mError != NO_ERROR) {
   4408         return 0;
   4409     }
   4410 
   4411     bool fakePublic = false;
   4412 
   4413     // Figure out the package and type we are looking in...
   4414 
   4415     const char16_t* packageEnd = NULL;
   4416     const char16_t* typeEnd = NULL;
   4417     const char16_t* const nameEnd = name+nameLen;
   4418     const char16_t* p = name;
   4419     while (p < nameEnd) {
   4420         if (*p == ':') packageEnd = p;
   4421         else if (*p == '/') typeEnd = p;
   4422         p++;
   4423     }
   4424     if (*name == '@') {
   4425         name++;
   4426         if (*name == '*') {
   4427             fakePublic = true;
   4428             name++;
   4429         }
   4430     }
   4431     if (name >= nameEnd) {
   4432         return 0;
   4433     }
   4434 
   4435     if (packageEnd) {
   4436         package = name;
   4437         packageLen = packageEnd-name;
   4438         name = packageEnd+1;
   4439     } else if (!package) {
   4440         return 0;
   4441     }
   4442 
   4443     if (typeEnd) {
   4444         type = name;
   4445         typeLen = typeEnd-name;
   4446         name = typeEnd+1;
   4447     } else if (!type) {
   4448         return 0;
   4449     }
   4450 
   4451     if (name >= nameEnd) {
   4452         return 0;
   4453     }
   4454     nameLen = nameEnd-name;
   4455 
   4456     if (kDebugTableNoisy) {
   4457         printf("Looking for identifier: type=%s, name=%s, package=%s\n",
   4458                 String8(type, typeLen).string(),
   4459                 String8(name, nameLen).string(),
   4460                 String8(package, packageLen).string());
   4461     }
   4462 
   4463     const String16 attr("attr");
   4464     const String16 attrPrivate("^attr-private");
   4465 
   4466     const size_t NG = mPackageGroups.size();
   4467     for (size_t ig=0; ig<NG; ig++) {
   4468         const PackageGroup* group = mPackageGroups[ig];
   4469 
   4470         if (strzcmp16(package, packageLen,
   4471                       group->name.string(), group->name.size())) {
   4472             if (kDebugTableNoisy) {
   4473                 printf("Skipping package group: %s\n", String8(group->name).string());
   4474             }
   4475             continue;
   4476         }
   4477 
   4478         const size_t packageCount = group->packages.size();
   4479         for (size_t pi = 0; pi < packageCount; pi++) {
   4480             const char16_t* targetType = type;
   4481             size_t targetTypeLen = typeLen;
   4482 
   4483             do {
   4484                 ssize_t ti = group->packages[pi]->typeStrings.indexOfString(
   4485                         targetType, targetTypeLen);
   4486                 if (ti < 0) {
   4487                     continue;
   4488                 }
   4489 
   4490                 ti += group->packages[pi]->typeIdOffset;
   4491 
   4492                 const uint32_t identifier = findEntry(group, ti, name, nameLen,
   4493                         outTypeSpecFlags);
   4494                 if (identifier != 0) {
   4495                     if (fakePublic && outTypeSpecFlags) {
   4496                         *outTypeSpecFlags |= ResTable_typeSpec::SPEC_PUBLIC;
   4497                     }
   4498                     return identifier;
   4499                 }
   4500             } while (strzcmp16(attr.string(), attr.size(), targetType, targetTypeLen) == 0
   4501                     && (targetType = attrPrivate.string())
   4502                     && (targetTypeLen = attrPrivate.size())
   4503             );
   4504         }
   4505         break;
   4506     }
   4507     return 0;
   4508 }
   4509 
   4510 uint32_t ResTable::findEntry(const PackageGroup* group, ssize_t typeIndex, const char16_t* name,
   4511         size_t nameLen, uint32_t* outTypeSpecFlags) const {
   4512     const TypeList& typeList = group->types[typeIndex];
   4513     const size_t typeCount = typeList.size();
   4514     for (size_t i = 0; i < typeCount; i++) {
   4515         const Type* t = typeList[i];
   4516         const ssize_t ei = t->package->keyStrings.indexOfString(name, nameLen);
   4517         if (ei < 0) {
   4518             continue;
   4519         }
   4520 
   4521         const size_t configCount = t->configs.size();
   4522         for (size_t j = 0; j < configCount; j++) {
   4523             const TypeVariant tv(t->configs[j]);
   4524             for (TypeVariant::iterator iter = tv.beginEntries();
   4525                  iter != tv.endEntries();
   4526                  iter++) {
   4527                 const ResTable_entry* entry = *iter;
   4528                 if (entry == NULL) {
   4529                     continue;
   4530                 }
   4531 
   4532                 if (dtohl(entry->key.index) == (size_t) ei) {
   4533                     uint32_t resId = Res_MAKEID(group->id - 1, typeIndex, iter.index());
   4534                     if (outTypeSpecFlags) {
   4535                         Entry result;
   4536                         if (getEntry(group, typeIndex, iter.index(), NULL, &result) != NO_ERROR) {
   4537                             ALOGW("Failed to find spec flags for 0x%08x", resId);
   4538                             return 0;
   4539                         }
   4540                         *outTypeSpecFlags = result.specFlags;
   4541                     }
   4542                     return resId;
   4543                 }
   4544             }
   4545         }
   4546     }
   4547     return 0;
   4548 }
   4549 
   4550 bool ResTable::expandResourceRef(const char16_t* refStr, size_t refLen,
   4551                                  String16* outPackage,
   4552                                  String16* outType,
   4553                                  String16* outName,
   4554                                  const String16* defType,
   4555                                  const String16* defPackage,
   4556                                  const char** outErrorMsg,
   4557                                  bool* outPublicOnly)
   4558 {
   4559     const char16_t* packageEnd = NULL;
   4560     const char16_t* typeEnd = NULL;
   4561     const char16_t* p = refStr;
   4562     const char16_t* const end = p + refLen;
   4563     while (p < end) {
   4564         if (*p == ':') packageEnd = p;
   4565         else if (*p == '/') {
   4566             typeEnd = p;
   4567             break;
   4568         }
   4569         p++;
   4570     }
   4571     p = refStr;
   4572     if (*p == '@') p++;
   4573 
   4574     if (outPublicOnly != NULL) {
   4575         *outPublicOnly = true;
   4576     }
   4577     if (*p == '*') {
   4578         p++;
   4579         if (outPublicOnly != NULL) {
   4580             *outPublicOnly = false;
   4581         }
   4582     }
   4583 
   4584     if (packageEnd) {
   4585         *outPackage = String16(p, packageEnd-p);
   4586         p = packageEnd+1;
   4587     } else {
   4588         if (!defPackage) {
   4589             if (outErrorMsg) {
   4590                 *outErrorMsg = "No resource package specified";
   4591             }
   4592             return false;
   4593         }
   4594         *outPackage = *defPackage;
   4595     }
   4596     if (typeEnd) {
   4597         *outType = String16(p, typeEnd-p);
   4598         p = typeEnd+1;
   4599     } else {
   4600         if (!defType) {
   4601             if (outErrorMsg) {
   4602                 *outErrorMsg = "No resource type specified";
   4603             }
   4604             return false;
   4605         }
   4606         *outType = *defType;
   4607     }
   4608     *outName = String16(p, end-p);
   4609     if(**outPackage == 0) {
   4610         if(outErrorMsg) {
   4611             *outErrorMsg = "Resource package cannot be an empty string";
   4612         }
   4613         return false;
   4614     }
   4615     if(**outType == 0) {
   4616         if(outErrorMsg) {
   4617             *outErrorMsg = "Resource type cannot be an empty string";
   4618         }
   4619         return false;
   4620     }
   4621     if(**outName == 0) {
   4622         if(outErrorMsg) {
   4623             *outErrorMsg = "Resource id cannot be an empty string";
   4624         }
   4625         return false;
   4626     }
   4627     return true;
   4628 }
   4629 
   4630 static uint32_t get_hex(char c, bool* outError)
   4631 {
   4632     if (c >= '0' && c <= '9') {
   4633         return c - '0';
   4634     } else if (c >= 'a' && c <= 'f') {
   4635         return c - 'a' + 0xa;
   4636     } else if (c >= 'A' && c <= 'F') {
   4637         return c - 'A' + 0xa;
   4638     }
   4639     *outError = true;
   4640     return 0;
   4641 }
   4642 
   4643 struct unit_entry
   4644 {
   4645     const char* name;
   4646     size_t len;
   4647     uint8_t type;
   4648     uint32_t unit;
   4649     float scale;
   4650 };
   4651 
   4652 static const unit_entry unitNames[] = {
   4653     { "px", strlen("px"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_PX, 1.0f },
   4654     { "dip", strlen("dip"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_DIP, 1.0f },
   4655     { "dp", strlen("dp"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_DIP, 1.0f },
   4656     { "sp", strlen("sp"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_SP, 1.0f },
   4657     { "pt", strlen("pt"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_PT, 1.0f },
   4658     { "in", strlen("in"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_IN, 1.0f },
   4659     { "mm", strlen("mm"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_MM, 1.0f },
   4660     { "%", strlen("%"), Res_value::TYPE_FRACTION, Res_value::COMPLEX_UNIT_FRACTION, 1.0f/100 },
   4661     { "%p", strlen("%p"), Res_value::TYPE_FRACTION, Res_value::COMPLEX_UNIT_FRACTION_PARENT, 1.0f/100 },
   4662     { NULL, 0, 0, 0, 0 }
   4663 };
   4664 
   4665 static bool parse_unit(const char* str, Res_value* outValue,
   4666                        float* outScale, const char** outEnd)
   4667 {
   4668     const char* end = str;
   4669     while (*end != 0 && !isspace((unsigned char)*end)) {
   4670         end++;
   4671     }
   4672     const size_t len = end-str;
   4673 
   4674     const char* realEnd = end;
   4675     while (*realEnd != 0 && isspace((unsigned char)*realEnd)) {
   4676         realEnd++;
   4677     }
   4678     if (*realEnd != 0) {
   4679         return false;
   4680     }
   4681 
   4682     const unit_entry* cur = unitNames;
   4683     while (cur->name) {
   4684         if (len == cur->len && strncmp(cur->name, str, len) == 0) {
   4685             outValue->dataType = cur->type;
   4686             outValue->data = cur->unit << Res_value::COMPLEX_UNIT_SHIFT;
   4687             *outScale = cur->scale;
   4688             *outEnd = end;
   4689             //printf("Found unit %s for %s\n", cur->name, str);
   4690             return true;
   4691         }
   4692         cur++;
   4693     }
   4694 
   4695     return false;
   4696 }
   4697 
   4698 bool U16StringToInt(const char16_t* s, size_t len, Res_value* outValue)
   4699 {
   4700     while (len > 0 && isspace16(*s)) {
   4701         s++;
   4702         len--;
   4703     }
   4704 
   4705     if (len <= 0) {
   4706         return false;
   4707     }
   4708 
   4709     size_t i = 0;
   4710     int64_t val = 0;
   4711     bool neg = false;
   4712 
   4713     if (*s == '-') {
   4714         neg = true;
   4715         i++;
   4716     }
   4717 
   4718     if (s[i] < '0' || s[i] > '9') {
   4719         return false;
   4720     }
   4721 
   4722     static_assert(std::is_same<uint32_t, Res_value::data_type>::value,
   4723                   "Res_value::data_type has changed. The range checks in this "
   4724                   "function are no longer correct.");
   4725 
   4726     // Decimal or hex?
   4727     bool isHex;
   4728     if (len > 1 && s[i] == '0' && s[i+1] == 'x') {
   4729         isHex = true;
   4730         i += 2;
   4731 
   4732         if (neg) {
   4733             return false;
   4734         }
   4735 
   4736         if (i == len) {
   4737             // Just u"0x"
   4738             return false;
   4739         }
   4740 
   4741         bool error = false;
   4742         while (i < len && !error) {
   4743             val = (val*16) + get_hex(s[i], &error);
   4744             i++;
   4745 
   4746             if (val > std::numeric_limits<uint32_t>::max()) {
   4747                 return false;
   4748             }
   4749         }
   4750         if (error) {
   4751             return false;
   4752         }
   4753     } else {
   4754         isHex = false;
   4755         while (i < len) {
   4756             if (s[i] < '0' || s[i] > '9') {
   4757                 return false;
   4758             }
   4759             val = (val*10) + s[i]-'0';
   4760             i++;
   4761 
   4762             if ((neg && -val < std::numeric_limits<int32_t>::min()) ||
   4763                 (!neg && val > std::numeric_limits<int32_t>::max())) {
   4764                 return false;
   4765             }
   4766         }
   4767     }
   4768 
   4769     if (neg) val = -val;
   4770 
   4771     while (i < len && isspace16(s[i])) {
   4772         i++;
   4773     }
   4774 
   4775     if (i != len) {
   4776         return false;
   4777     }
   4778 
   4779     if (outValue) {
   4780         outValue->dataType =
   4781             isHex ? outValue->TYPE_INT_HEX : outValue->TYPE_INT_DEC;
   4782         outValue->data = static_cast<Res_value::data_type>(val);
   4783     }
   4784     return true;
   4785 }
   4786 
   4787 bool ResTable::stringToInt(const char16_t* s, size_t len, Res_value* outValue)
   4788 {
   4789     return U16StringToInt(s, len, outValue);
   4790 }
   4791 
   4792 bool ResTable::stringToFloat(const char16_t* s, size_t len, Res_value* outValue)
   4793 {
   4794     while (len > 0 && isspace16(*s)) {
   4795         s++;
   4796         len--;
   4797     }
   4798 
   4799     if (len <= 0) {
   4800         return false;
   4801     }
   4802 
   4803     char buf[128];
   4804     int i=0;
   4805     while (len > 0 && *s != 0 && i < 126) {
   4806         if (*s > 255) {
   4807             return false;
   4808         }
   4809         buf[i++] = *s++;
   4810         len--;
   4811     }
   4812 
   4813     if (len > 0) {
   4814         return false;
   4815     }
   4816     if ((buf[0] < '0' || buf[0] > '9') && buf[0] != '.' && buf[0] != '-' && buf[0] != '+') {
   4817         return false;
   4818     }
   4819 
   4820     buf[i] = 0;
   4821     const char* end;
   4822     float f = strtof(buf, (char**)&end);
   4823 
   4824     if (*end != 0 && !isspace((unsigned char)*end)) {
   4825         // Might be a unit...
   4826         float scale;
   4827         if (parse_unit(end, outValue, &scale, &end)) {
   4828             f *= scale;
   4829             const bool neg = f < 0;
   4830             if (neg) f = -f;
   4831             uint64_t bits = (uint64_t)(f*(1<<23)+.5f);
   4832             uint32_t radix;
   4833             uint32_t shift;
   4834             if ((bits&0x7fffff) == 0) {
   4835                 // Always use 23p0 if there is no fraction, just to make
   4836                 // things easier to read.
   4837                 radix = Res_value::COMPLEX_RADIX_23p0;
   4838                 shift = 23;
   4839             } else if ((bits&0xffffffffff800000LL) == 0) {
   4840                 // Magnitude is zero -- can fit in 0 bits of precision.
   4841                 radix = Res_value::COMPLEX_RADIX_0p23;
   4842                 shift = 0;
   4843             } else if ((bits&0xffffffff80000000LL) == 0) {
   4844                 // Magnitude can fit in 8 bits of precision.
   4845                 radix = Res_value::COMPLEX_RADIX_8p15;
   4846                 shift = 8;
   4847             } else if ((bits&0xffffff8000000000LL) == 0) {
   4848                 // Magnitude can fit in 16 bits of precision.
   4849                 radix = Res_value::COMPLEX_RADIX_16p7;
   4850                 shift = 16;
   4851             } else {
   4852                 // Magnitude needs entire range, so no fractional part.
   4853                 radix = Res_value::COMPLEX_RADIX_23p0;
   4854                 shift = 23;
   4855             }
   4856             int32_t mantissa = (int32_t)(
   4857                 (bits>>shift) & Res_value::COMPLEX_MANTISSA_MASK);
   4858             if (neg) {
   4859                 mantissa = (-mantissa) & Res_value::COMPLEX_MANTISSA_MASK;
   4860             }
   4861             outValue->data |=
   4862                 (radix<<Res_value::COMPLEX_RADIX_SHIFT)
   4863                 | (mantissa<<Res_value::COMPLEX_MANTISSA_SHIFT);
   4864             //printf("Input value: %f 0x%016Lx, mult: %f, radix: %d, shift: %d, final: 0x%08x\n",
   4865             //       f * (neg ? -1 : 1), bits, f*(1<<23),
   4866             //       radix, shift, outValue->data);
   4867             return true;
   4868         }
   4869         return false;
   4870     }
   4871 
   4872     while (*end != 0 && isspace((unsigned char)*end)) {
   4873         end++;
   4874     }
   4875 
   4876     if (*end == 0) {
   4877         if (outValue) {
   4878             outValue->dataType = outValue->TYPE_FLOAT;
   4879             *(float*)(&outValue->data) = f;
   4880             return true;
   4881         }
   4882     }
   4883 
   4884     return false;
   4885 }
   4886 
   4887 bool ResTable::stringToValue(Res_value* outValue, String16* outString,
   4888                              const char16_t* s, size_t len,
   4889                              bool preserveSpaces, bool coerceType,
   4890                              uint32_t attrID,
   4891                              const String16* defType,
   4892                              const String16* defPackage,
   4893                              Accessor* accessor,
   4894                              void* accessorCookie,
   4895                              uint32_t attrType,
   4896                              bool enforcePrivate) const
   4897 {
   4898     bool localizationSetting = accessor != NULL && accessor->getLocalizationSetting();
   4899     const char* errorMsg = NULL;
   4900 
   4901     outValue->size = sizeof(Res_value);
   4902     outValue->res0 = 0;
   4903 
   4904     // First strip leading/trailing whitespace.  Do this before handling
   4905     // escapes, so they can be used to force whitespace into the string.
   4906     if (!preserveSpaces) {
   4907         while (len > 0 && isspace16(*s)) {
   4908             s++;
   4909             len--;
   4910         }
   4911         while (len > 0 && isspace16(s[len-1])) {
   4912             len--;
   4913         }
   4914         // If the string ends with '\', then we keep the space after it.
   4915         if (len > 0 && s[len-1] == '\\' && s[len] != 0) {
   4916             len++;
   4917         }
   4918     }
   4919 
   4920     //printf("Value for: %s\n", String8(s, len).string());
   4921 
   4922     uint32_t l10nReq = ResTable_map::L10N_NOT_REQUIRED;
   4923     uint32_t attrMin = 0x80000000, attrMax = 0x7fffffff;
   4924     bool fromAccessor = false;
   4925     if (attrID != 0 && !Res_INTERNALID(attrID)) {
   4926         const ssize_t p = getResourcePackageIndex(attrID);
   4927         const bag_entry* bag;
   4928         ssize_t cnt = p >= 0 ? lockBag(attrID, &bag) : -1;
   4929         //printf("For attr 0x%08x got bag of %d\n", attrID, cnt);
   4930         if (cnt >= 0) {
   4931             while (cnt > 0) {
   4932                 //printf("Entry 0x%08x = 0x%08x\n", bag->map.name.ident, bag->map.value.data);
   4933                 switch (bag->map.name.ident) {
   4934                 case ResTable_map::ATTR_TYPE:
   4935                     attrType = bag->map.value.data;
   4936                     break;
   4937                 case ResTable_map::ATTR_MIN:
   4938                     attrMin = bag->map.value.data;
   4939                     break;
   4940                 case ResTable_map::ATTR_MAX:
   4941                     attrMax = bag->map.value.data;
   4942                     break;
   4943                 case ResTable_map::ATTR_L10N:
   4944                     l10nReq = bag->map.value.data;
   4945                     break;
   4946                 }
   4947                 bag++;
   4948                 cnt--;
   4949             }
   4950             unlockBag(bag);
   4951         } else if (accessor && accessor->getAttributeType(attrID, &attrType)) {
   4952             fromAccessor = true;
   4953             if (attrType == ResTable_map::TYPE_ENUM
   4954                     || attrType == ResTable_map::TYPE_FLAGS
   4955                     || attrType == ResTable_map::TYPE_INTEGER) {
   4956                 accessor->getAttributeMin(attrID, &attrMin);
   4957                 accessor->getAttributeMax(attrID, &attrMax);
   4958             }
   4959             if (localizationSetting) {
   4960                 l10nReq = accessor->getAttributeL10N(attrID);
   4961             }
   4962         }
   4963     }
   4964 
   4965     const bool canStringCoerce =
   4966         coerceType && (attrType&ResTable_map::TYPE_STRING) != 0;
   4967 
   4968     if (*s == '@') {
   4969         outValue->dataType = outValue->TYPE_REFERENCE;
   4970 
   4971         // Note: we don't check attrType here because the reference can
   4972         // be to any other type; we just need to count on the client making
   4973         // sure the referenced type is correct.
   4974 
   4975         //printf("Looking up ref: %s\n", String8(s, len).string());
   4976 
   4977         // It's a reference!
   4978         if (len == 5 && s[1]=='n' && s[2]=='u' && s[3]=='l' && s[4]=='l') {
   4979             // Special case @null as undefined. This will be converted by
   4980             // AssetManager to TYPE_NULL with data DATA_NULL_UNDEFINED.
   4981             outValue->data = 0;
   4982             return true;
   4983         } else if (len == 6 && s[1]=='e' && s[2]=='m' && s[3]=='p' && s[4]=='t' && s[5]=='y') {
   4984             // Special case @empty as explicitly defined empty value.
   4985             outValue->dataType = Res_value::TYPE_NULL;
   4986             outValue->data = Res_value::DATA_NULL_EMPTY;
   4987             return true;
   4988         } else {
   4989             bool createIfNotFound = false;
   4990             const char16_t* resourceRefName;
   4991             int resourceNameLen;
   4992             if (len > 2 && s[1] == '+') {
   4993                 createIfNotFound = true;
   4994                 resourceRefName = s + 2;
   4995                 resourceNameLen = len - 2;
   4996             } else if (len > 2 && s[1] == '*') {
   4997                 enforcePrivate = false;
   4998                 resourceRefName = s + 2;
   4999                 resourceNameLen = len - 2;
   5000             } else {
   5001                 createIfNotFound = false;
   5002                 resourceRefName = s + 1;
   5003                 resourceNameLen = len - 1;
   5004             }
   5005             String16 package, type, name;
   5006             if (!expandResourceRef(resourceRefName,resourceNameLen, &package, &type, &name,
   5007                                    defType, defPackage, &errorMsg)) {
   5008                 if (accessor != NULL) {
   5009                     accessor->reportError(accessorCookie, errorMsg);
   5010                 }
   5011                 return false;
   5012             }
   5013 
   5014             uint32_t specFlags = 0;
   5015             uint32_t rid = identifierForName(name.string(), name.size(), type.string(),
   5016                     type.size(), package.string(), package.size(), &specFlags);
   5017             if (rid != 0) {
   5018                 if (enforcePrivate) {
   5019                     if (accessor == NULL || accessor->getAssetsPackage() != package) {
   5020                         if ((specFlags&ResTable_typeSpec::SPEC_PUBLIC) == 0) {
   5021                             if (accessor != NULL) {
   5022                                 accessor->reportError(accessorCookie, "Resource is not public.");
   5023                             }
   5024                             return false;
   5025                         }
   5026                     }
   5027                 }
   5028 
   5029                 if (accessor) {
   5030                     rid = Res_MAKEID(
   5031                         accessor->getRemappedPackage(Res_GETPACKAGE(rid)),
   5032                         Res_GETTYPE(rid), Res_GETENTRY(rid));
   5033                     if (kDebugTableNoisy) {
   5034                         ALOGI("Incl %s:%s/%s: 0x%08x\n",
   5035                                 String8(package).string(), String8(type).string(),
   5036                                 String8(name).string(), rid);
   5037                     }
   5038                 }
   5039 
   5040                 uint32_t packageId = Res_GETPACKAGE(rid) + 1;
   5041                 if (packageId != APP_PACKAGE_ID && packageId != SYS_PACKAGE_ID) {
   5042                     outValue->dataType = Res_value::TYPE_DYNAMIC_REFERENCE;
   5043                 }
   5044                 outValue->data = rid;
   5045                 return true;
   5046             }
   5047 
   5048             if (accessor) {
   5049                 uint32_t rid = accessor->getCustomResourceWithCreation(package, type, name,
   5050                                                                        createIfNotFound);
   5051                 if (rid != 0) {
   5052                     if (kDebugTableNoisy) {
   5053                         ALOGI("Pckg %s:%s/%s: 0x%08x\n",
   5054                                 String8(package).string(), String8(type).string(),
   5055                                 String8(name).string(), rid);
   5056                     }
   5057                     uint32_t packageId = Res_GETPACKAGE(rid) + 1;
   5058                     if (packageId == 0x00) {
   5059                         outValue->data = rid;
   5060                         outValue->dataType = Res_value::TYPE_DYNAMIC_REFERENCE;
   5061                         return true;
   5062                     } else if (packageId == APP_PACKAGE_ID || packageId == SYS_PACKAGE_ID) {
   5063                         // We accept packageId's generated as 0x01 in order to support
   5064                         // building the android system resources
   5065                         outValue->data = rid;
   5066                         return true;
   5067                     }
   5068                 }
   5069             }
   5070         }
   5071 
   5072         if (accessor != NULL) {
   5073             accessor->reportError(accessorCookie, "No resource found that matches the given name");
   5074         }
   5075         return false;
   5076     }
   5077 
   5078     // if we got to here, and localization is required and it's not a reference,
   5079     // complain and bail.
   5080     if (l10nReq == ResTable_map::L10N_SUGGESTED) {
   5081         if (localizationSetting) {
   5082             if (accessor != NULL) {
   5083                 accessor->reportError(accessorCookie, "This attribute must be localized.");
   5084             }
   5085         }
   5086     }
   5087 
   5088     if (*s == '#') {
   5089         // It's a color!  Convert to an integer of the form 0xaarrggbb.
   5090         uint32_t color = 0;
   5091         bool error = false;
   5092         if (len == 4) {
   5093             outValue->dataType = outValue->TYPE_INT_COLOR_RGB4;
   5094             color |= 0xFF000000;
   5095             color |= get_hex(s[1], &error) << 20;
   5096             color |= get_hex(s[1], &error) << 16;
   5097             color |= get_hex(s[2], &error) << 12;
   5098             color |= get_hex(s[2], &error) << 8;
   5099             color |= get_hex(s[3], &error) << 4;
   5100             color |= get_hex(s[3], &error);
   5101         } else if (len == 5) {
   5102             outValue->dataType = outValue->TYPE_INT_COLOR_ARGB4;
   5103             color |= get_hex(s[1], &error) << 28;
   5104             color |= get_hex(s[1], &error) << 24;
   5105             color |= get_hex(s[2], &error) << 20;
   5106             color |= get_hex(s[2], &error) << 16;
   5107             color |= get_hex(s[3], &error) << 12;
   5108             color |= get_hex(s[3], &error) << 8;
   5109             color |= get_hex(s[4], &error) << 4;
   5110             color |= get_hex(s[4], &error);
   5111         } else if (len == 7) {
   5112             outValue->dataType = outValue->TYPE_INT_COLOR_RGB8;
   5113             color |= 0xFF000000;
   5114             color |= get_hex(s[1], &error) << 20;
   5115             color |= get_hex(s[2], &error) << 16;
   5116             color |= get_hex(s[3], &error) << 12;
   5117             color |= get_hex(s[4], &error) << 8;
   5118             color |= get_hex(s[5], &error) << 4;
   5119             color |= get_hex(s[6], &error);
   5120         } else if (len == 9) {
   5121             outValue->dataType = outValue->TYPE_INT_COLOR_ARGB8;
   5122             color |= get_hex(s[1], &error) << 28;
   5123             color |= get_hex(s[2], &error) << 24;
   5124             color |= get_hex(s[3], &error) << 20;
   5125             color |= get_hex(s[4], &error) << 16;
   5126             color |= get_hex(s[5], &error) << 12;
   5127             color |= get_hex(s[6], &error) << 8;
   5128             color |= get_hex(s[7], &error) << 4;
   5129             color |= get_hex(s[8], &error);
   5130         } else {
   5131             error = true;
   5132         }
   5133         if (!error) {
   5134             if ((attrType&ResTable_map::TYPE_COLOR) == 0) {
   5135                 if (!canStringCoerce) {
   5136                     if (accessor != NULL) {
   5137                         accessor->reportError(accessorCookie,
   5138                                 "Color types not allowed");
   5139                     }
   5140                     return false;
   5141                 }
   5142             } else {
   5143                 outValue->data = color;
   5144                 //printf("Color input=%s, output=0x%x\n", String8(s, len).string(), color);
   5145                 return true;
   5146             }
   5147         } else {
   5148             if ((attrType&ResTable_map::TYPE_COLOR) != 0) {
   5149                 if (accessor != NULL) {
   5150                     accessor->reportError(accessorCookie, "Color value not valid --"
   5151                             " must be #rgb, #argb, #rrggbb, or #aarrggbb");
   5152                 }
   5153                 #if 0
   5154                 fprintf(stderr, "%s: Color ID %s value %s is not valid\n",
   5155                         "Resource File", //(const char*)in->getPrintableSource(),
   5156                         String8(*curTag).string(),
   5157                         String8(s, len).string());
   5158                 #endif
   5159                 return false;
   5160             }
   5161         }
   5162     }
   5163 
   5164     if (*s == '?') {
   5165         outValue->dataType = outValue->TYPE_ATTRIBUTE;
   5166 
   5167         // Note: we don't check attrType here because the reference can
   5168         // be to any other type; we just need to count on the client making
   5169         // sure the referenced type is correct.
   5170 
   5171         //printf("Looking up attr: %s\n", String8(s, len).string());
   5172 
   5173         static const String16 attr16("attr");
   5174         String16 package, type, name;
   5175         if (!expandResourceRef(s+1, len-1, &package, &type, &name,
   5176                                &attr16, defPackage, &errorMsg)) {
   5177             if (accessor != NULL) {
   5178                 accessor->reportError(accessorCookie, errorMsg);
   5179             }
   5180             return false;
   5181         }
   5182 
   5183         //printf("Pkg: %s, Type: %s, Name: %s\n",
   5184         //       String8(package).string(), String8(type).string(),
   5185         //       String8(name).string());
   5186         uint32_t specFlags = 0;
   5187         uint32_t rid =
   5188             identifierForName(name.string(), name.size(),
   5189                               type.string(), type.size(),
   5190                               package.string(), package.size(), &specFlags);
   5191         if (rid != 0) {
   5192             if (enforcePrivate) {
   5193                 if ((specFlags&ResTable_typeSpec::SPEC_PUBLIC) == 0) {
   5194                     if (accessor != NULL) {
   5195                         accessor->reportError(accessorCookie, "Attribute is not public.");
   5196                     }
   5197                     return false;
   5198                 }
   5199             }
   5200             if (!accessor) {
   5201                 outValue->data = rid;
   5202                 return true;
   5203             }
   5204             rid = Res_MAKEID(
   5205                 accessor->getRemappedPackage(Res_GETPACKAGE(rid)),
   5206                 Res_GETTYPE(rid), Res_GETENTRY(rid));
   5207             //printf("Incl %s:%s/%s: 0x%08x\n",
   5208             //       String8(package).string(), String8(type).string(),
   5209             //       String8(name).string(), rid);
   5210             outValue->data = rid;
   5211             return true;
   5212         }
   5213 
   5214         if (accessor) {
   5215             uint32_t rid = accessor->getCustomResource(package, type, name);
   5216             if (rid != 0) {
   5217                 //printf("Mine %s:%s/%s: 0x%08x\n",
   5218                 //       String8(package).string(), String8(type).string(),
   5219                 //       String8(name).string(), rid);
   5220                 outValue->data = rid;
   5221                 return true;
   5222             }
   5223         }
   5224 
   5225         if (accessor != NULL) {
   5226             accessor->reportError(accessorCookie, "No resource found that matches the given name");
   5227         }
   5228         return false;
   5229     }
   5230 
   5231     if (stringToInt(s, len, outValue)) {
   5232         if ((attrType&ResTable_map::TYPE_INTEGER) == 0) {
   5233             // If this type does not allow integers, but does allow floats,
   5234             // fall through on this error case because the float type should
   5235             // be able to accept any integer value.
   5236             if (!canStringCoerce && (attrType&ResTable_map::TYPE_FLOAT) == 0) {
   5237                 if (accessor != NULL) {
   5238                     accessor->reportError(accessorCookie, "Integer types not allowed");
   5239                 }
   5240                 return false;
   5241             }
   5242         } else {
   5243             if (((int32_t)outValue->data) < ((int32_t)attrMin)
   5244                     || ((int32_t)outValue->data) > ((int32_t)attrMax)) {
   5245                 if (accessor != NULL) {
   5246                     accessor->reportError(accessorCookie, "Integer value out of range");
   5247                 }
   5248                 return false;
   5249             }
   5250             return true;
   5251         }
   5252     }
   5253 
   5254     if (stringToFloat(s, len, outValue)) {
   5255         if (outValue->dataType == Res_value::TYPE_DIMENSION) {
   5256             if ((attrType&ResTable_map::TYPE_DIMENSION) != 0) {
   5257                 return true;
   5258             }
   5259             if (!canStringCoerce) {
   5260                 if (accessor != NULL) {
   5261                     accessor->reportError(accessorCookie, "Dimension types not allowed");
   5262                 }
   5263                 return false;
   5264             }
   5265         } else if (outValue->dataType == Res_value::TYPE_FRACTION) {
   5266             if ((attrType&ResTable_map::TYPE_FRACTION) != 0) {
   5267                 return true;
   5268             }
   5269             if (!canStringCoerce) {
   5270                 if (accessor != NULL) {
   5271                     accessor->reportError(accessorCookie, "Fraction types not allowed");
   5272                 }
   5273                 return false;
   5274             }
   5275         } else if ((attrType&ResTable_map::TYPE_FLOAT) == 0) {
   5276             if (!canStringCoerce) {
   5277                 if (accessor != NULL) {
   5278                     accessor->reportError(accessorCookie, "Float types not allowed");
   5279                 }
   5280                 return false;
   5281             }
   5282         } else {
   5283             return true;
   5284         }
   5285     }
   5286 
   5287     if (len == 4) {
   5288         if ((s[0] == 't' || s[0] == 'T') &&
   5289             (s[1] == 'r' || s[1] == 'R') &&
   5290             (s[2] == 'u' || s[2] == 'U') &&
   5291             (s[3] == 'e' || s[3] == 'E')) {
   5292             if ((attrType&ResTable_map::TYPE_BOOLEAN) == 0) {
   5293                 if (!canStringCoerce) {
   5294                     if (accessor != NULL) {
   5295                         accessor->reportError(accessorCookie, "Boolean types not allowed");
   5296                     }
   5297                     return false;
   5298                 }
   5299             } else {
   5300                 outValue->dataType = outValue->TYPE_INT_BOOLEAN;
   5301                 outValue->data = (uint32_t)-1;
   5302                 return true;
   5303             }
   5304         }
   5305     }
   5306 
   5307     if (len == 5) {
   5308         if ((s[0] == 'f' || s[0] == 'F') &&
   5309             (s[1] == 'a' || s[1] == 'A') &&
   5310             (s[2] == 'l' || s[2] == 'L') &&
   5311             (s[3] == 's' || s[3] == 'S') &&
   5312             (s[4] == 'e' || s[4] == 'E')) {
   5313             if ((attrType&ResTable_map::TYPE_BOOLEAN) == 0) {
   5314                 if (!canStringCoerce) {
   5315                     if (accessor != NULL) {
   5316                         accessor->reportError(accessorCookie, "Boolean types not allowed");
   5317                     }
   5318                     return false;
   5319                 }
   5320             } else {
   5321                 outValue->dataType = outValue->TYPE_INT_BOOLEAN;
   5322                 outValue->data = 0;
   5323                 return true;
   5324             }
   5325         }
   5326     }
   5327 
   5328     if ((attrType&ResTable_map::TYPE_ENUM) != 0) {
   5329         const ssize_t p = getResourcePackageIndex(attrID);
   5330         const bag_entry* bag;
   5331         ssize_t cnt = p >= 0 ? lockBag(attrID, &bag) : -1;
   5332         //printf("Got %d for enum\n", cnt);
   5333         if (cnt >= 0) {
   5334             resource_name rname;
   5335             while (cnt > 0) {
   5336                 if (!Res_INTERNALID(bag->map.name.ident)) {
   5337                     //printf("Trying attr #%08x\n", bag->map.name.ident);
   5338                     if (getResourceName(bag->map.name.ident, false, &rname)) {
   5339                         #if 0
   5340                         printf("Matching %s against %s (0x%08x)\n",
   5341                                String8(s, len).string(),
   5342                                String8(rname.name, rname.nameLen).string(),
   5343                                bag->map.name.ident);
   5344                         #endif
   5345                         if (strzcmp16(s, len, rname.name, rname.nameLen) == 0) {
   5346                             outValue->dataType = bag->map.value.dataType;
   5347                             outValue->data = bag->map.value.data;
   5348                             unlockBag(bag);
   5349                             return true;
   5350                         }
   5351                     }
   5352 
   5353                 }
   5354                 bag++;
   5355                 cnt--;
   5356             }
   5357             unlockBag(bag);
   5358         }
   5359 
   5360         if (fromAccessor) {
   5361             if (accessor->getAttributeEnum(attrID, s, len, outValue)) {
   5362                 return true;
   5363             }
   5364         }
   5365     }
   5366 
   5367     if ((attrType&ResTable_map::TYPE_FLAGS) != 0) {
   5368         const ssize_t p = getResourcePackageIndex(attrID);
   5369         const bag_entry* bag;
   5370         ssize_t cnt = p >= 0 ? lockBag(attrID, &bag) : -1;
   5371         //printf("Got %d for flags\n", cnt);
   5372         if (cnt >= 0) {
   5373             bool failed = false;
   5374             resource_name rname;
   5375             outValue->dataType = Res_value::TYPE_INT_HEX;
   5376             outValue->data = 0;
   5377             const char16_t* end = s + len;
   5378             const char16_t* pos = s;
   5379             while (pos < end && !failed) {
   5380                 const char16_t* start = pos;
   5381                 pos++;
   5382                 while (pos < end && *pos != '|') {
   5383                     pos++;
   5384                 }
   5385                 //printf("Looking for: %s\n", String8(start, pos-start).string());
   5386                 const bag_entry* bagi = bag;
   5387                 ssize_t i;
   5388                 for (i=0; i<cnt; i++, bagi++) {
   5389                     if (!Res_INTERNALID(bagi->map.name.ident)) {
   5390                         //printf("Trying attr #%08x\n", bagi->map.name.ident);
   5391                         if (getResourceName(bagi->map.name.ident, false, &rname)) {
   5392                             #if 0
   5393                             printf("Matching %s against %s (0x%08x)\n",
   5394                                    String8(start,pos-start).string(),
   5395                                    String8(rname.name, rname.nameLen).string(),
   5396                                    bagi->map.name.ident);
   5397                             #endif
   5398                             if (strzcmp16(start, pos-start, rname.name, rname.nameLen) == 0) {
   5399                                 outValue->data |= bagi->map.value.data;
   5400                                 break;
   5401                             }
   5402                         }
   5403                     }
   5404                 }
   5405                 if (i >= cnt) {
   5406                     // Didn't find this flag identifier.
   5407                     failed = true;
   5408                 }
   5409                 if (pos < end) {
   5410                     pos++;
   5411                 }
   5412             }
   5413             unlockBag(bag);
   5414             if (!failed) {
   5415                 //printf("Final flag value: 0x%lx\n", outValue->data);
   5416                 return true;
   5417             }
   5418         }
   5419 
   5420 
   5421         if (fromAccessor) {
   5422             if (accessor->getAttributeFlags(attrID, s, len, outValue)) {
   5423                 //printf("Final flag value: 0x%lx\n", outValue->data);
   5424                 return true;
   5425             }
   5426         }
   5427     }
   5428 
   5429     if ((attrType&ResTable_map::TYPE_STRING) == 0) {
   5430         if (accessor != NULL) {
   5431             accessor->reportError(accessorCookie, "String types not allowed");
   5432         }
   5433         return false;
   5434     }
   5435 
   5436     // Generic string handling...
   5437     outValue->dataType = outValue->TYPE_STRING;
   5438     if (outString) {
   5439         bool failed = collectString(outString, s, len, preserveSpaces, &errorMsg);
   5440         if (accessor != NULL) {
   5441             accessor->reportError(accessorCookie, errorMsg);
   5442         }
   5443         return failed;
   5444     }
   5445 
   5446     return true;
   5447 }
   5448 
   5449 bool ResTable::collectString(String16* outString,
   5450                              const char16_t* s, size_t len,
   5451                              bool preserveSpaces,
   5452                              const char** outErrorMsg,
   5453                              bool append)
   5454 {
   5455     String16 tmp;
   5456 
   5457     char quoted = 0;
   5458     const char16_t* p = s;
   5459     while (p < (s+len)) {
   5460         while (p < (s+len)) {
   5461             const char16_t c = *p;
   5462             if (c == '\\') {
   5463                 break;
   5464             }
   5465             if (!preserveSpaces) {
   5466                 if (quoted == 0 && isspace16(c)
   5467                     && (c != ' ' || isspace16(*(p+1)))) {
   5468                     break;
   5469                 }
   5470                 if (c == '"' && (quoted == 0 || quoted == '"')) {
   5471                     break;
   5472                 }
   5473                 if (c == '\'' && (quoted == 0 || quoted == '\'')) {
   5474                     /*
   5475                      * In practice, when people write ' instead of \'
   5476                      * in a string, they are doing it by accident
   5477                      * instead of really meaning to use ' as a quoting
   5478                      * character.  Warn them so they don't lose it.
   5479                      */
   5480                     if (outErrorMsg) {
   5481                         *outErrorMsg = "Apostrophe not preceded by \\";
   5482                     }
   5483                     return false;
   5484                 }
   5485             }
   5486             p++;
   5487         }
   5488         if (p < (s+len)) {
   5489             if (p > s) {
   5490                 tmp.append(String16(s, p-s));
   5491             }
   5492             if (!preserveSpaces && (*p == '"' || *p == '\'')) {
   5493                 if (quoted == 0) {
   5494                     quoted = *p;
   5495                 } else {
   5496                     quoted = 0;
   5497                 }
   5498                 p++;
   5499             } else if (!preserveSpaces && isspace16(*p)) {
   5500                 // Space outside of a quote -- consume all spaces and
   5501                 // leave a single plain space char.
   5502                 tmp.append(String16(" "));
   5503                 p++;
   5504                 while (p < (s+len) && isspace16(*p)) {
   5505                     p++;
   5506                 }
   5507             } else if (*p == '\\') {
   5508                 p++;
   5509                 if (p < (s+len)) {
   5510                     switch (*p) {
   5511                     case 't':
   5512                         tmp.append(String16("\t"));
   5513                         break;
   5514                     case 'n':
   5515                         tmp.append(String16("\n"));
   5516                         break;
   5517                     case '#':
   5518                         tmp.append(String16("#"));
   5519                         break;
   5520                     case '@':
   5521                         tmp.append(String16("@"));
   5522                         break;
   5523                     case '?':
   5524                         tmp.append(String16("?"));
   5525                         break;
   5526                     case '"':
   5527                         tmp.append(String16("\""));
   5528                         break;
   5529                     case '\'':
   5530                         tmp.append(String16("'"));
   5531                         break;
   5532                     case '\\':
   5533                         tmp.append(String16("\\"));
   5534                         break;
   5535                     case 'u':
   5536                     {
   5537                         char16_t chr = 0;
   5538                         int i = 0;
   5539                         while (i < 4 && p[1] != 0) {
   5540                             p++;
   5541                             i++;
   5542                             int c;
   5543                             if (*p >= '0' && *p <= '9') {
   5544                                 c = *p - '0';
   5545                             } else if (*p >= 'a' && *p <= 'f') {
   5546                                 c = *p - 'a' + 10;
   5547                             } else if (*p >= 'A' && *p <= 'F') {
   5548                                 c = *p - 'A' + 10;
   5549                             } else {
   5550                                 if (outErrorMsg) {
   5551                                     *outErrorMsg = "Bad character in \\u unicode escape sequence";
   5552                                 }
   5553                                 return false;
   5554                             }
   5555                             chr = (chr<<4) | c;
   5556                         }
   5557                         tmp.append(String16(&chr, 1));
   5558                     } break;
   5559                     default:
   5560                         // ignore unknown escape chars.
   5561                         break;
   5562                     }
   5563                     p++;
   5564                 }
   5565             }
   5566             len -= (p-s);
   5567             s = p;
   5568         }
   5569     }
   5570 
   5571     if (tmp.size() != 0) {
   5572         if (len > 0) {
   5573             tmp.append(String16(s, len));
   5574         }
   5575         if (append) {
   5576             outString->append(tmp);
   5577         } else {
   5578             outString->setTo(tmp);
   5579         }
   5580     } else {
   5581         if (append) {
   5582             outString->append(String16(s, len));
   5583         } else {
   5584             outString->setTo(s, len);
   5585         }
   5586     }
   5587 
   5588     return true;
   5589 }
   5590 
   5591 size_t ResTable::getBasePackageCount() const
   5592 {
   5593     if (mError != NO_ERROR) {
   5594         return 0;
   5595     }
   5596     return mPackageGroups.size();
   5597 }
   5598 
   5599 const String16 ResTable::getBasePackageName(size_t idx) const
   5600 {
   5601     if (mError != NO_ERROR) {
   5602         return String16();
   5603     }
   5604     LOG_FATAL_IF(idx >= mPackageGroups.size(),
   5605                  "Requested package index %d past package count %d",
   5606                  (int)idx, (int)mPackageGroups.size());
   5607     return mPackageGroups[idx]->name;
   5608 }
   5609 
   5610 uint32_t ResTable::getBasePackageId(size_t idx) const
   5611 {
   5612     if (mError != NO_ERROR) {
   5613         return 0;
   5614     }
   5615     LOG_FATAL_IF(idx >= mPackageGroups.size(),
   5616                  "Requested package index %d past package count %d",
   5617                  (int)idx, (int)mPackageGroups.size());
   5618     return mPackageGroups[idx]->id;
   5619 }
   5620 
   5621 uint32_t ResTable::getLastTypeIdForPackage(size_t idx) const
   5622 {
   5623     if (mError != NO_ERROR) {
   5624         return 0;
   5625     }
   5626     LOG_FATAL_IF(idx >= mPackageGroups.size(),
   5627             "Requested package index %d past package count %d",
   5628             (int)idx, (int)mPackageGroups.size());
   5629     const PackageGroup* const group = mPackageGroups[idx];
   5630     return group->largestTypeId;
   5631 }
   5632 
   5633 size_t ResTable::getTableCount() const
   5634 {
   5635     return mHeaders.size();
   5636 }
   5637 
   5638 const ResStringPool* ResTable::getTableStringBlock(size_t index) const
   5639 {
   5640     return &mHeaders[index]->values;
   5641 }
   5642 
   5643 int32_t ResTable::getTableCookie(size_t index) const
   5644 {
   5645     return mHeaders[index]->cookie;
   5646 }
   5647 
   5648 const DynamicRefTable* ResTable::getDynamicRefTableForCookie(int32_t cookie) const
   5649 {
   5650     const size_t N = mPackageGroups.size();
   5651     for (size_t i = 0; i < N; i++) {
   5652         const PackageGroup* pg = mPackageGroups[i];
   5653         size_t M = pg->packages.size();
   5654         for (size_t j = 0; j < M; j++) {
   5655             if (pg->packages[j]->header->cookie == cookie) {
   5656                 return &pg->dynamicRefTable;
   5657             }
   5658         }
   5659     }
   5660     return NULL;
   5661 }
   5662 
   5663 void ResTable::getConfigurations(Vector<ResTable_config>* configs, bool ignoreMipmap) const
   5664 {
   5665     const size_t packageCount = mPackageGroups.size();
   5666     for (size_t i = 0; i < packageCount; i++) {
   5667         const PackageGroup* packageGroup = mPackageGroups[i];
   5668         const size_t typeCount = packageGroup->types.size();
   5669         for (size_t j = 0; j < typeCount; j++) {
   5670             const TypeList& typeList = packageGroup->types[j];
   5671             const size_t numTypes = typeList.size();
   5672             for (size_t k = 0; k < numTypes; k++) {
   5673                 const Type* type = typeList[k];
   5674                 const ResStringPool& typeStrings = type->package->typeStrings;
   5675                 if (ignoreMipmap && typeStrings.string8ObjectAt(
   5676                             type->typeSpec->id - 1) == "mipmap") {
   5677                     continue;
   5678                 }
   5679 
   5680                 const size_t numConfigs = type->configs.size();
   5681                 for (size_t m = 0; m < numConfigs; m++) {
   5682                     const ResTable_type* config = type->configs[m];
   5683                     ResTable_config cfg;
   5684                     memset(&cfg, 0, sizeof(ResTable_config));
   5685                     cfg.copyFromDtoH(config->config);
   5686                     // only insert unique
   5687                     const size_t N = configs->size();
   5688                     size_t n;
   5689                     for (n = 0; n < N; n++) {
   5690                         if (0 == (*configs)[n].compare(cfg)) {
   5691                             break;
   5692                         }
   5693                     }
   5694                     // if we didn't find it
   5695                     if (n == N) {
   5696                         configs->add(cfg);
   5697                     }
   5698                 }
   5699             }
   5700         }
   5701     }
   5702 }
   5703 
   5704 void ResTable::getLocales(Vector<String8>* locales) const
   5705 {
   5706     Vector<ResTable_config> configs;
   5707     ALOGV("calling getConfigurations");
   5708     getConfigurations(&configs);
   5709     ALOGV("called getConfigurations size=%d", (int)configs.size());
   5710     const size_t I = configs.size();
   5711 
   5712     char locale[RESTABLE_MAX_LOCALE_LEN];
   5713     for (size_t i=0; i<I; i++) {
   5714         configs[i].getBcp47Locale(locale);
   5715         const size_t J = locales->size();
   5716         size_t j;
   5717         for (j=0; j<J; j++) {
   5718             if (0 == strcmp(locale, (*locales)[j].string())) {
   5719                 break;
   5720             }
   5721         }
   5722         if (j == J) {
   5723             locales->add(String8(locale));
   5724         }
   5725     }
   5726 }
   5727 
   5728 StringPoolRef::StringPoolRef(const ResStringPool* pool, uint32_t index)
   5729     : mPool(pool), mIndex(index) {}
   5730 
   5731 StringPoolRef::StringPoolRef()
   5732     : mPool(NULL), mIndex(0) {}
   5733 
   5734 const char* StringPoolRef::string8(size_t* outLen) const {
   5735     if (mPool != NULL) {
   5736         return mPool->string8At(mIndex, outLen);
   5737     }
   5738     if (outLen != NULL) {
   5739         *outLen = 0;
   5740     }
   5741     return NULL;
   5742 }
   5743 
   5744 const char16_t* StringPoolRef::string16(size_t* outLen) const {
   5745     if (mPool != NULL) {
   5746         return mPool->stringAt(mIndex, outLen);
   5747     }
   5748     if (outLen != NULL) {
   5749         *outLen = 0;
   5750     }
   5751     return NULL;
   5752 }
   5753 
   5754 bool ResTable::getResourceFlags(uint32_t resID, uint32_t* outFlags) const {
   5755     if (mError != NO_ERROR) {
   5756         return false;
   5757     }
   5758 
   5759     const ssize_t p = getResourcePackageIndex(resID);
   5760     const int t = Res_GETTYPE(resID);
   5761     const int e = Res_GETENTRY(resID);
   5762 
   5763     if (p < 0) {
   5764         if (Res_GETPACKAGE(resID)+1 == 0) {
   5765             ALOGW("No package identifier when getting flags for resource number 0x%08x", resID);
   5766         } else {
   5767             ALOGW("No known package when getting flags for resource number 0x%08x", resID);
   5768         }
   5769         return false;
   5770     }
   5771     if (t < 0) {
   5772         ALOGW("No type identifier when getting flags for resource number 0x%08x", resID);
   5773         return false;
   5774     }
   5775 
   5776     const PackageGroup* const grp = mPackageGroups[p];
   5777     if (grp == NULL) {
   5778         ALOGW("Bad identifier when getting flags for resource number 0x%08x", resID);
   5779         return false;
   5780     }
   5781 
   5782     Entry entry;
   5783     status_t err = getEntry(grp, t, e, NULL, &entry);
   5784     if (err != NO_ERROR) {
   5785         return false;
   5786     }
   5787 
   5788     *outFlags = entry.specFlags;
   5789     return true;
   5790 }
   5791 
   5792 status_t ResTable::getEntry(
   5793         const PackageGroup* packageGroup, int typeIndex, int entryIndex,
   5794         const ResTable_config* config,
   5795         Entry* outEntry) const
   5796 {
   5797     const TypeList& typeList = packageGroup->types[typeIndex];
   5798     if (typeList.isEmpty()) {
   5799         ALOGV("Skipping entry type index 0x%02x because type is NULL!\n", typeIndex);
   5800         return BAD_TYPE;
   5801     }
   5802 
   5803     const ResTable_type* bestType = NULL;
   5804     uint32_t bestOffset = ResTable_type::NO_ENTRY;
   5805     const Package* bestPackage = NULL;
   5806     uint32_t specFlags = 0;
   5807     uint8_t actualTypeIndex = typeIndex;
   5808     ResTable_config bestConfig;
   5809     memset(&bestConfig, 0, sizeof(bestConfig));
   5810 
   5811     // Iterate over the Types of each package.
   5812     const size_t typeCount = typeList.size();
   5813     for (size_t i = 0; i < typeCount; i++) {
   5814         const Type* const typeSpec = typeList[i];
   5815 
   5816         int realEntryIndex = entryIndex;
   5817         int realTypeIndex = typeIndex;
   5818         bool currentTypeIsOverlay = false;
   5819 
   5820         // Runtime overlay packages provide a mapping of app resource
   5821         // ID to package resource ID.
   5822         if (typeSpec->idmapEntries.hasEntries()) {
   5823             uint16_t overlayEntryIndex;
   5824             if (typeSpec->idmapEntries.lookup(entryIndex, &overlayEntryIndex) != NO_ERROR) {
   5825                 // No such mapping exists
   5826                 continue;
   5827             }
   5828             realEntryIndex = overlayEntryIndex;
   5829             realTypeIndex = typeSpec->idmapEntries.overlayTypeId() - 1;
   5830             currentTypeIsOverlay = true;
   5831         }
   5832 
   5833         if (static_cast<size_t>(realEntryIndex) >= typeSpec->entryCount) {
   5834             ALOGW("For resource 0x%08x, entry index(%d) is beyond type entryCount(%d)",
   5835                     Res_MAKEID(packageGroup->id - 1, typeIndex, entryIndex),
   5836                     entryIndex, static_cast<int>(typeSpec->entryCount));
   5837             // We should normally abort here, but some legacy apps declare
   5838             // resources in the 'android' package (old bug in AAPT).
   5839             continue;
   5840         }
   5841 
   5842         // Aggregate all the flags for each package that defines this entry.
   5843         if (typeSpec->typeSpecFlags != NULL) {
   5844             specFlags |= dtohl(typeSpec->typeSpecFlags[realEntryIndex]);
   5845         } else {
   5846             specFlags = -1;
   5847         }
   5848 
   5849         const size_t numConfigs = typeSpec->configs.size();
   5850         for (size_t c = 0; c < numConfigs; c++) {
   5851             const ResTable_type* const thisType = typeSpec->configs[c];
   5852             if (thisType == NULL) {
   5853                 continue;
   5854             }
   5855 
   5856             ResTable_config thisConfig;
   5857             thisConfig.copyFromDtoH(thisType->config);
   5858 
   5859             // Check to make sure this one is valid for the current parameters.
   5860             if (config != NULL && !thisConfig.match(*config)) {
   5861                 continue;
   5862             }
   5863 
   5864             // Check if there is the desired entry in this type.
   5865             const uint32_t* const eindex = reinterpret_cast<const uint32_t*>(
   5866                     reinterpret_cast<const uint8_t*>(thisType) + dtohs(thisType->header.headerSize));
   5867 
   5868             uint32_t thisOffset = dtohl(eindex[realEntryIndex]);
   5869             if (thisOffset == ResTable_type::NO_ENTRY) {
   5870                 // There is no entry for this index and configuration.
   5871                 continue;
   5872             }
   5873 
   5874             if (bestType != NULL) {
   5875                 // Check if this one is less specific than the last found.  If so,
   5876                 // we will skip it.  We check starting with things we most care
   5877                 // about to those we least care about.
   5878                 if (!thisConfig.isBetterThan(bestConfig, config)) {
   5879                     if (!currentTypeIsOverlay || thisConfig.compare(bestConfig) != 0) {
   5880                         continue;
   5881                     }
   5882                 }
   5883             }
   5884 
   5885             bestType = thisType;
   5886             bestOffset = thisOffset;
   5887             bestConfig = thisConfig;
   5888             bestPackage = typeSpec->package;
   5889             actualTypeIndex = realTypeIndex;
   5890 
   5891             // If no config was specified, any type will do, so skip
   5892             if (config == NULL) {
   5893                 break;
   5894             }
   5895         }
   5896     }
   5897 
   5898     if (bestType == NULL) {
   5899         return BAD_INDEX;
   5900     }
   5901 
   5902     bestOffset += dtohl(bestType->entriesStart);
   5903 
   5904     if (bestOffset > (dtohl(bestType->header.size)-sizeof(ResTable_entry))) {
   5905         ALOGW("ResTable_entry at 0x%x is beyond type chunk data 0x%x",
   5906                 bestOffset, dtohl(bestType->header.size));
   5907         return BAD_TYPE;
   5908     }
   5909     if ((bestOffset & 0x3) != 0) {
   5910         ALOGW("ResTable_entry at 0x%x is not on an integer boundary", bestOffset);
   5911         return BAD_TYPE;
   5912     }
   5913 
   5914     const ResTable_entry* const entry = reinterpret_cast<const ResTable_entry*>(
   5915             reinterpret_cast<const uint8_t*>(bestType) + bestOffset);
   5916     if (dtohs(entry->size) < sizeof(*entry)) {
   5917         ALOGW("ResTable_entry size 0x%x is too small", dtohs(entry->size));
   5918         return BAD_TYPE;
   5919     }
   5920 
   5921     if (outEntry != NULL) {
   5922         outEntry->entry = entry;
   5923         outEntry->config = bestConfig;
   5924         outEntry->type = bestType;
   5925         outEntry->specFlags = specFlags;
   5926         outEntry->package = bestPackage;
   5927         outEntry->typeStr = StringPoolRef(&bestPackage->typeStrings, actualTypeIndex - bestPackage->typeIdOffset);
   5928         outEntry->keyStr = StringPoolRef(&bestPackage->keyStrings, dtohl(entry->key.index));
   5929     }
   5930     return NO_ERROR;
   5931 }
   5932 
   5933 status_t ResTable::parsePackage(const ResTable_package* const pkg,
   5934                                 const Header* const header)
   5935 {
   5936     const uint8_t* base = (const uint8_t*)pkg;
   5937     status_t err = validate_chunk(&pkg->header, sizeof(*pkg) - sizeof(pkg->typeIdOffset),
   5938                                   header->dataEnd, "ResTable_package");
   5939     if (err != NO_ERROR) {
   5940         return (mError=err);
   5941     }
   5942 
   5943     const uint32_t pkgSize = dtohl(pkg->header.size);
   5944 
   5945     if (dtohl(pkg->typeStrings) >= pkgSize) {
   5946         ALOGW("ResTable_package type strings at 0x%x are past chunk size 0x%x.",
   5947              dtohl(pkg->typeStrings), pkgSize);
   5948         return (mError=BAD_TYPE);
   5949     }
   5950     if ((dtohl(pkg->typeStrings)&0x3) != 0) {
   5951         ALOGW("ResTable_package type strings at 0x%x is not on an integer boundary.",
   5952              dtohl(pkg->typeStrings));
   5953         return (mError=BAD_TYPE);
   5954     }
   5955     if (dtohl(pkg->keyStrings) >= pkgSize) {
   5956         ALOGW("ResTable_package key strings at 0x%x are past chunk size 0x%x.",
   5957              dtohl(pkg->keyStrings), pkgSize);
   5958         return (mError=BAD_TYPE);
   5959     }
   5960     if ((dtohl(pkg->keyStrings)&0x3) != 0) {
   5961         ALOGW("ResTable_package key strings at 0x%x is not on an integer boundary.",
   5962              dtohl(pkg->keyStrings));
   5963         return (mError=BAD_TYPE);
   5964     }
   5965 
   5966     uint32_t id = dtohl(pkg->id);
   5967     KeyedVector<uint8_t, IdmapEntries> idmapEntries;
   5968 
   5969     if (header->resourceIDMap != NULL) {
   5970         uint8_t targetPackageId = 0;
   5971         status_t err = parseIdmap(header->resourceIDMap, header->resourceIDMapSize, &targetPackageId, &idmapEntries);
   5972         if (err != NO_ERROR) {
   5973             ALOGW("Overlay is broken");
   5974             return (mError=err);
   5975         }
   5976         id = targetPackageId;
   5977     }
   5978 
   5979     if (id >= 256) {
   5980         LOG_ALWAYS_FATAL("Package id out of range");
   5981         return NO_ERROR;
   5982     } else if (id == 0) {
   5983         // This is a library so assign an ID
   5984         id = mNextPackageId++;
   5985     }
   5986 
   5987     PackageGroup* group = NULL;
   5988     Package* package = new Package(this, header, pkg);
   5989     if (package == NULL) {
   5990         return (mError=NO_MEMORY);
   5991     }
   5992 
   5993     err = package->typeStrings.setTo(base+dtohl(pkg->typeStrings),
   5994                                    header->dataEnd-(base+dtohl(pkg->typeStrings)));
   5995     if (err != NO_ERROR) {
   5996         delete group;
   5997         delete package;
   5998         return (mError=err);
   5999     }
   6000 
   6001     err = package->keyStrings.setTo(base+dtohl(pkg->keyStrings),
   6002                                   header->dataEnd-(base+dtohl(pkg->keyStrings)));
   6003     if (err != NO_ERROR) {
   6004         delete group;
   6005         delete package;
   6006         return (mError=err);
   6007     }
   6008 
   6009     size_t idx = mPackageMap[id];
   6010     if (idx == 0) {
   6011         idx = mPackageGroups.size() + 1;
   6012 
   6013         char16_t tmpName[sizeof(pkg->name)/sizeof(pkg->name[0])];
   6014         strcpy16_dtoh(tmpName, pkg->name, sizeof(pkg->name)/sizeof(pkg->name[0]));
   6015         group = new PackageGroup(this, String16(tmpName), id);
   6016         if (group == NULL) {
   6017             delete package;
   6018             return (mError=NO_MEMORY);
   6019         }
   6020 
   6021         err = mPackageGroups.add(group);
   6022         if (err < NO_ERROR) {
   6023             return (mError=err);
   6024         }
   6025 
   6026         mPackageMap[id] = static_cast<uint8_t>(idx);
   6027 
   6028         // Find all packages that reference this package
   6029         size_t N = mPackageGroups.size();
   6030         for (size_t i = 0; i < N; i++) {
   6031             mPackageGroups[i]->dynamicRefTable.addMapping(
   6032                     group->name, static_cast<uint8_t>(group->id));
   6033         }
   6034     } else {
   6035         group = mPackageGroups.itemAt(idx - 1);
   6036         if (group == NULL) {
   6037             return (mError=UNKNOWN_ERROR);
   6038         }
   6039     }
   6040 
   6041     err = group->packages.add(package);
   6042     if (err < NO_ERROR) {
   6043         return (mError=err);
   6044     }
   6045 
   6046     // Iterate through all chunks.
   6047     const ResChunk_header* chunk =
   6048         (const ResChunk_header*)(((const uint8_t*)pkg)
   6049                                  + dtohs(pkg->header.headerSize));
   6050     const uint8_t* endPos = ((const uint8_t*)pkg) + dtohs(pkg->header.size);
   6051     while (((const uint8_t*)chunk) <= (endPos-sizeof(ResChunk_header)) &&
   6052            ((const uint8_t*)chunk) <= (endPos-dtohl(chunk->size))) {
   6053         if (kDebugTableNoisy) {
   6054             ALOGV("PackageChunk: type=0x%x, headerSize=0x%x, size=0x%x, pos=%p\n",
   6055                     dtohs(chunk->type), dtohs(chunk->headerSize), dtohl(chunk->size),
   6056                     (void*)(((const uint8_t*)chunk) - ((const uint8_t*)header->header)));
   6057         }
   6058         const size_t csize = dtohl(chunk->size);
   6059         const uint16_t ctype = dtohs(chunk->type);
   6060         if (ctype == RES_TABLE_TYPE_SPEC_TYPE) {
   6061             const ResTable_typeSpec* typeSpec = (const ResTable_typeSpec*)(chunk);
   6062             err = validate_chunk(&typeSpec->header, sizeof(*typeSpec),
   6063                                  endPos, "ResTable_typeSpec");
   6064             if (err != NO_ERROR) {
   6065                 return (mError=err);
   6066             }
   6067 
   6068             const size_t typeSpecSize = dtohl(typeSpec->header.size);
   6069             const size_t newEntryCount = dtohl(typeSpec->entryCount);
   6070 
   6071             if (kDebugLoadTableNoisy) {
   6072                 ALOGI("TypeSpec off %p: type=0x%x, headerSize=0x%x, size=%p\n",
   6073                         (void*)(base-(const uint8_t*)chunk),
   6074                         dtohs(typeSpec->header.type),
   6075                         dtohs(typeSpec->header.headerSize),
   6076                         (void*)typeSpecSize);
   6077             }
   6078             // look for block overrun or int overflow when multiplying by 4
   6079             if ((dtohl(typeSpec->entryCount) > (INT32_MAX/sizeof(uint32_t))
   6080                     || dtohs(typeSpec->header.headerSize)+(sizeof(uint32_t)*newEntryCount)
   6081                     > typeSpecSize)) {
   6082                 ALOGW("ResTable_typeSpec entry index to %p extends beyond chunk end %p.",
   6083                         (void*)(dtohs(typeSpec->header.headerSize) + (sizeof(uint32_t)*newEntryCount)),
   6084                         (void*)typeSpecSize);
   6085                 return (mError=BAD_TYPE);
   6086             }
   6087 
   6088             if (typeSpec->id == 0) {
   6089                 ALOGW("ResTable_type has an id of 0.");
   6090                 return (mError=BAD_TYPE);
   6091             }
   6092 
   6093             if (newEntryCount > 0) {
   6094                 uint8_t typeIndex = typeSpec->id - 1;
   6095                 ssize_t idmapIndex = idmapEntries.indexOfKey(typeSpec->id);
   6096                 if (idmapIndex >= 0) {
   6097                     typeIndex = idmapEntries[idmapIndex].targetTypeId() - 1;
   6098                 }
   6099 
   6100                 TypeList& typeList = group->types.editItemAt(typeIndex);
   6101                 if (!typeList.isEmpty()) {
   6102                     const Type* existingType = typeList[0];
   6103                     if (existingType->entryCount != newEntryCount && idmapIndex < 0) {
   6104                         ALOGW("ResTable_typeSpec entry count inconsistent: given %d, previously %d",
   6105                                 (int) newEntryCount, (int) existingType->entryCount);
   6106                         // We should normally abort here, but some legacy apps declare
   6107                         // resources in the 'android' package (old bug in AAPT).
   6108                     }
   6109                 }
   6110 
   6111                 Type* t = new Type(header, package, newEntryCount);
   6112                 t->typeSpec = typeSpec;
   6113                 t->typeSpecFlags = (const uint32_t*)(
   6114                         ((const uint8_t*)typeSpec) + dtohs(typeSpec->header.headerSize));
   6115                 if (idmapIndex >= 0) {
   6116                     t->idmapEntries = idmapEntries[idmapIndex];
   6117                 }
   6118                 typeList.add(t);
   6119                 group->largestTypeId = max(group->largestTypeId, typeSpec->id);
   6120             } else {
   6121                 ALOGV("Skipping empty ResTable_typeSpec for type %d", typeSpec->id);
   6122             }
   6123 
   6124         } else if (ctype == RES_TABLE_TYPE_TYPE) {
   6125             const ResTable_type* type = (const ResTable_type*)(chunk);
   6126             err = validate_chunk(&type->header, sizeof(*type)-sizeof(ResTable_config)+4,
   6127                                  endPos, "ResTable_type");
   6128             if (err != NO_ERROR) {
   6129                 return (mError=err);
   6130             }
   6131 
   6132             const uint32_t typeSize = dtohl(type->header.size);
   6133             const size_t newEntryCount = dtohl(type->entryCount);
   6134 
   6135             if (kDebugLoadTableNoisy) {
   6136                 printf("Type off %p: type=0x%x, headerSize=0x%x, size=%u\n",
   6137                         (void*)(base-(const uint8_t*)chunk),
   6138                         dtohs(type->header.type),
   6139                         dtohs(type->header.headerSize),
   6140                         typeSize);
   6141             }
   6142             if (dtohs(type->header.headerSize)+(sizeof(uint32_t)*newEntryCount) > typeSize) {
   6143                 ALOGW("ResTable_type entry index to %p extends beyond chunk end 0x%x.",
   6144                         (void*)(dtohs(type->header.headerSize) + (sizeof(uint32_t)*newEntryCount)),
   6145                         typeSize);
   6146                 return (mError=BAD_TYPE);
   6147             }
   6148 
   6149             if (newEntryCount != 0
   6150                 && dtohl(type->entriesStart) > (typeSize-sizeof(ResTable_entry))) {
   6151                 ALOGW("ResTable_type entriesStart at 0x%x extends beyond chunk end 0x%x.",
   6152                      dtohl(type->entriesStart), typeSize);
   6153                 return (mError=BAD_TYPE);
   6154             }
   6155 
   6156             if (type->id == 0) {
   6157                 ALOGW("ResTable_type has an id of 0.");
   6158                 return (mError=BAD_TYPE);
   6159             }
   6160 
   6161             if (newEntryCount > 0) {
   6162                 uint8_t typeIndex = type->id - 1;
   6163                 ssize_t idmapIndex = idmapEntries.indexOfKey(type->id);
   6164                 if (idmapIndex >= 0) {
   6165                     typeIndex = idmapEntries[idmapIndex].targetTypeId() - 1;
   6166                 }
   6167 
   6168                 TypeList& typeList = group->types.editItemAt(typeIndex);
   6169                 if (typeList.isEmpty()) {
   6170                     ALOGE("No TypeSpec for type %d", type->id);
   6171                     return (mError=BAD_TYPE);
   6172                 }
   6173 
   6174                 Type* t = typeList.editItemAt(typeList.size() - 1);
   6175                 if (newEntryCount != t->entryCount) {
   6176                     ALOGE("ResTable_type entry count inconsistent: given %d, previously %d",
   6177                         (int)newEntryCount, (int)t->entryCount);
   6178                     return (mError=BAD_TYPE);
   6179                 }
   6180 
   6181                 if (t->package != package) {
   6182                     ALOGE("No TypeSpec for type %d", type->id);
   6183                     return (mError=BAD_TYPE);
   6184                 }
   6185 
   6186                 t->configs.add(type);
   6187 
   6188                 if (kDebugTableGetEntry) {
   6189                     ResTable_config thisConfig;
   6190                     thisConfig.copyFromDtoH(type->config);
   6191                     ALOGI("Adding config to type %d: %s\n", type->id,
   6192                             thisConfig.toString().string());
   6193                 }
   6194             } else {
   6195                 ALOGV("Skipping empty ResTable_type for type %d", type->id);
   6196             }
   6197 
   6198         } else if (ctype == RES_TABLE_LIBRARY_TYPE) {
   6199             if (group->dynamicRefTable.entries().size() == 0) {
   6200                 status_t err = group->dynamicRefTable.load((const ResTable_lib_header*) chunk);
   6201                 if (err != NO_ERROR) {
   6202                     return (mError=err);
   6203                 }
   6204 
   6205                 // Fill in the reference table with the entries we already know about.
   6206                 size_t N = mPackageGroups.size();
   6207                 for (size_t i = 0; i < N; i++) {
   6208                     group->dynamicRefTable.addMapping(mPackageGroups[i]->name, mPackageGroups[i]->id);
   6209                 }
   6210             } else {
   6211                 ALOGW("Found multiple library tables, ignoring...");
   6212             }
   6213         } else {
   6214             status_t err = validate_chunk(chunk, sizeof(ResChunk_header),
   6215                                           endPos, "ResTable_package:unknown");
   6216             if (err != NO_ERROR) {
   6217                 return (mError=err);
   6218             }
   6219         }
   6220         chunk = (const ResChunk_header*)
   6221             (((const uint8_t*)chunk) + csize);
   6222     }
   6223 
   6224     return NO_ERROR;
   6225 }
   6226 
   6227 DynamicRefTable::DynamicRefTable(uint8_t packageId)
   6228     : mAssignedPackageId(packageId)
   6229 {
   6230     memset(mLookupTable, 0, sizeof(mLookupTable));
   6231 
   6232     // Reserved package ids
   6233     mLookupTable[APP_PACKAGE_ID] = APP_PACKAGE_ID;
   6234     mLookupTable[SYS_PACKAGE_ID] = SYS_PACKAGE_ID;
   6235 }
   6236 
   6237 status_t DynamicRefTable::load(const ResTable_lib_header* const header)
   6238 {
   6239     const uint32_t entryCount = dtohl(header->count);
   6240     const uint32_t sizeOfEntries = sizeof(ResTable_lib_entry) * entryCount;
   6241     const uint32_t expectedSize = dtohl(header->header.size) - dtohl(header->header.headerSize);
   6242     if (sizeOfEntries > expectedSize) {
   6243         ALOGE("ResTable_lib_header size %u is too small to fit %u entries (x %u).",
   6244                 expectedSize, entryCount, (uint32_t)sizeof(ResTable_lib_entry));
   6245         return UNKNOWN_ERROR;
   6246     }
   6247 
   6248     const ResTable_lib_entry* entry = (const ResTable_lib_entry*)(((uint8_t*) header) +
   6249             dtohl(header->header.headerSize));
   6250     for (uint32_t entryIndex = 0; entryIndex < entryCount; entryIndex++) {
   6251         uint32_t packageId = dtohl(entry->packageId);
   6252         char16_t tmpName[sizeof(entry->packageName) / sizeof(char16_t)];
   6253         strcpy16_dtoh(tmpName, entry->packageName, sizeof(entry->packageName) / sizeof(char16_t));
   6254         if (kDebugLibNoisy) {
   6255             ALOGV("Found lib entry %s with id %d\n", String8(tmpName).string(),
   6256                     dtohl(entry->packageId));
   6257         }
   6258         if (packageId >= 256) {
   6259             ALOGE("Bad package id 0x%08x", packageId);
   6260             return UNKNOWN_ERROR;
   6261         }
   6262         mEntries.replaceValueFor(String16(tmpName), (uint8_t) packageId);
   6263         entry = entry + 1;
   6264     }
   6265     return NO_ERROR;
   6266 }
   6267 
   6268 status_t DynamicRefTable::addMappings(const DynamicRefTable& other) {
   6269     if (mAssignedPackageId != other.mAssignedPackageId) {
   6270         return UNKNOWN_ERROR;
   6271     }
   6272 
   6273     const size_t entryCount = other.mEntries.size();
   6274     for (size_t i = 0; i < entryCount; i++) {
   6275         ssize_t index = mEntries.indexOfKey(other.mEntries.keyAt(i));
   6276         if (index < 0) {
   6277             mEntries.add(other.mEntries.keyAt(i), other.mEntries[i]);
   6278         } else {
   6279             if (other.mEntries[i] != mEntries[index]) {
   6280                 return UNKNOWN_ERROR;
   6281             }
   6282         }
   6283     }
   6284 
   6285     // Merge the lookup table. No entry can conflict
   6286     // (value of 0 means not set).
   6287     for (size_t i = 0; i < 256; i++) {
   6288         if (mLookupTable[i] != other.mLookupTable[i]) {
   6289             if (mLookupTable[i] == 0) {
   6290                 mLookupTable[i] = other.mLookupTable[i];
   6291             } else if (other.mLookupTable[i] != 0) {
   6292                 return UNKNOWN_ERROR;
   6293             }
   6294         }
   6295     }
   6296     return NO_ERROR;
   6297 }
   6298 
   6299 status_t DynamicRefTable::addMapping(const String16& packageName, uint8_t packageId)
   6300 {
   6301     ssize_t index = mEntries.indexOfKey(packageName);
   6302     if (index < 0) {
   6303         return UNKNOWN_ERROR;
   6304     }
   6305     mLookupTable[mEntries.valueAt(index)] = packageId;
   6306     return NO_ERROR;
   6307 }
   6308 
   6309 status_t DynamicRefTable::lookupResourceId(uint32_t* resId) const {
   6310     uint32_t res = *resId;
   6311     size_t packageId = Res_GETPACKAGE(res) + 1;
   6312 
   6313     if (packageId == APP_PACKAGE_ID) {
   6314         // No lookup needs to be done, app package IDs are absolute.
   6315         return NO_ERROR;
   6316     }
   6317 
   6318     if (packageId == 0) {
   6319         // The package ID is 0x00. That means that a shared library is accessing
   6320         // its own local resource, so we fix up the resource with the calling
   6321         // package ID.
   6322         *resId |= ((uint32_t) mAssignedPackageId) << 24;
   6323         return NO_ERROR;
   6324     }
   6325 
   6326     // Do a proper lookup.
   6327     uint8_t translatedId = mLookupTable[packageId];
   6328     if (translatedId == 0) {
   6329         ALOGV("DynamicRefTable(0x%02x): No mapping for build-time package ID 0x%02x.",
   6330                 (uint8_t)mAssignedPackageId, (uint8_t)packageId);
   6331         for (size_t i = 0; i < 256; i++) {
   6332             if (mLookupTable[i] != 0) {
   6333                 ALOGV("e[0x%02x] -> 0x%02x", (uint8_t)i, mLookupTable[i]);
   6334             }
   6335         }
   6336         return UNKNOWN_ERROR;
   6337     }
   6338 
   6339     *resId = (res & 0x00ffffff) | (((uint32_t) translatedId) << 24);
   6340     return NO_ERROR;
   6341 }
   6342 
   6343 status_t DynamicRefTable::lookupResourceValue(Res_value* value) const {
   6344     if (value->dataType != Res_value::TYPE_DYNAMIC_REFERENCE) {
   6345         return NO_ERROR;
   6346     }
   6347 
   6348     status_t err = lookupResourceId(&value->data);
   6349     if (err != NO_ERROR) {
   6350         return err;
   6351     }
   6352 
   6353     value->dataType = Res_value::TYPE_REFERENCE;
   6354     return NO_ERROR;
   6355 }
   6356 
   6357 struct IdmapTypeMap {
   6358     ssize_t overlayTypeId;
   6359     size_t entryOffset;
   6360     Vector<uint32_t> entryMap;
   6361 };
   6362 
   6363 status_t ResTable::createIdmap(const ResTable& overlay,
   6364         uint32_t targetCrc, uint32_t overlayCrc,
   6365         const char* targetPath, const char* overlayPath,
   6366         void** outData, size_t* outSize) const
   6367 {
   6368     // see README for details on the format of map
   6369     if (mPackageGroups.size() == 0) {
   6370         ALOGW("idmap: target package has no package groups, cannot create idmap\n");
   6371         return UNKNOWN_ERROR;
   6372     }
   6373 
   6374     if (mPackageGroups[0]->packages.size() == 0) {
   6375         ALOGW("idmap: target package has no packages in its first package group, "
   6376                 "cannot create idmap\n");
   6377         return UNKNOWN_ERROR;
   6378     }
   6379 
   6380     KeyedVector<uint8_t, IdmapTypeMap> map;
   6381 
   6382     // overlaid packages are assumed to contain only one package group
   6383     const PackageGroup* pg = mPackageGroups[0];
   6384 
   6385     // starting size is header
   6386     *outSize = ResTable::IDMAP_HEADER_SIZE_BYTES;
   6387 
   6388     // target package id and number of types in map
   6389     *outSize += 2 * sizeof(uint16_t);
   6390 
   6391     // overlay packages are assumed to contain only one package group
   6392     const ResTable_package* overlayPackageStruct = overlay.mPackageGroups[0]->packages[0]->package;
   6393     char16_t tmpName[sizeof(overlayPackageStruct->name)/sizeof(overlayPackageStruct->name[0])];
   6394     strcpy16_dtoh(tmpName, overlayPackageStruct->name, sizeof(overlayPackageStruct->name)/sizeof(overlayPackageStruct->name[0]));
   6395     const String16 overlayPackage(tmpName);
   6396 
   6397     for (size_t typeIndex = 0; typeIndex < pg->types.size(); ++typeIndex) {
   6398         const TypeList& typeList = pg->types[typeIndex];
   6399         if (typeList.isEmpty()) {
   6400             continue;
   6401         }
   6402 
   6403         const Type* typeConfigs = typeList[0];
   6404 
   6405         IdmapTypeMap typeMap;
   6406         typeMap.overlayTypeId = -1;
   6407         typeMap.entryOffset = 0;
   6408 
   6409         for (size_t entryIndex = 0; entryIndex < typeConfigs->entryCount; ++entryIndex) {
   6410             uint32_t resID = Res_MAKEID(pg->id - 1, typeIndex, entryIndex);
   6411             resource_name resName;
   6412             if (!this->getResourceName(resID, false, &resName)) {
   6413                 if (typeMap.entryMap.isEmpty()) {
   6414                     typeMap.entryOffset++;
   6415                 }
   6416                 continue;
   6417             }
   6418 
   6419             const String16 overlayType(resName.type, resName.typeLen);
   6420             const String16 overlayName(resName.name, resName.nameLen);
   6421             uint32_t overlayResID = overlay.identifierForName(overlayName.string(),
   6422                                                               overlayName.size(),
   6423                                                               overlayType.string(),
   6424                                                               overlayType.size(),
   6425                                                               overlayPackage.string(),
   6426                                                               overlayPackage.size());
   6427             if (overlayResID == 0) {
   6428                 if (typeMap.entryMap.isEmpty()) {
   6429                     typeMap.entryOffset++;
   6430                 }
   6431                 continue;
   6432             }
   6433 
   6434             if (typeMap.overlayTypeId == -1) {
   6435                 typeMap.overlayTypeId = Res_GETTYPE(overlayResID) + 1;
   6436             }
   6437 
   6438             if (Res_GETTYPE(overlayResID) + 1 != static_cast<size_t>(typeMap.overlayTypeId)) {
   6439                 ALOGE("idmap: can't mix type ids in entry map. Resource 0x%08x maps to 0x%08x"
   6440                         " but entries should map to resources of type %02zx",
   6441                         resID, overlayResID, typeMap.overlayTypeId);
   6442                 return BAD_TYPE;
   6443             }
   6444 
   6445             if (typeMap.entryOffset + typeMap.entryMap.size() < entryIndex) {
   6446                 // pad with 0xffffffff's (indicating non-existing entries) before adding this entry
   6447                 size_t index = typeMap.entryMap.size();
   6448                 size_t numItems = entryIndex - (typeMap.entryOffset + index);
   6449                 if (typeMap.entryMap.insertAt(0xffffffff, index, numItems) < 0) {
   6450                     return NO_MEMORY;
   6451                 }
   6452             }
   6453             typeMap.entryMap.add(Res_GETENTRY(overlayResID));
   6454         }
   6455 
   6456         if (!typeMap.entryMap.isEmpty()) {
   6457             if (map.add(static_cast<uint8_t>(typeIndex), typeMap) < 0) {
   6458                 return NO_MEMORY;
   6459             }
   6460             *outSize += (4 * sizeof(uint16_t)) + (typeMap.entryMap.size() * sizeof(uint32_t));
   6461         }
   6462     }
   6463 
   6464     if (map.isEmpty()) {
   6465         ALOGW("idmap: no resources in overlay package present in base package");
   6466         return UNKNOWN_ERROR;
   6467     }
   6468 
   6469     if ((*outData = malloc(*outSize)) == NULL) {
   6470         return NO_MEMORY;
   6471     }
   6472 
   6473     uint32_t* data = (uint32_t*)*outData;
   6474     *data++ = htodl(IDMAP_MAGIC);
   6475     *data++ = htodl(IDMAP_CURRENT_VERSION);
   6476     *data++ = htodl(targetCrc);
   6477     *data++ = htodl(overlayCrc);
   6478     const char* paths[] = { targetPath, overlayPath };
   6479     for (int j = 0; j < 2; ++j) {
   6480         char* p = (char*)data;
   6481         const char* path = paths[j];
   6482         const size_t I = strlen(path);
   6483         if (I > 255) {
   6484             ALOGV("path exceeds expected 255 characters: %s\n", path);
   6485             return UNKNOWN_ERROR;
   6486         }
   6487         for (size_t i = 0; i < 256; ++i) {
   6488             *p++ = i < I ? path[i] : '\0';
   6489         }
   6490         data += 256 / sizeof(uint32_t);
   6491     }
   6492     const size_t mapSize = map.size();
   6493     uint16_t* typeData = reinterpret_cast<uint16_t*>(data);
   6494     *typeData++ = htods(pg->id);
   6495     *typeData++ = htods(mapSize);
   6496     for (size_t i = 0; i < mapSize; ++i) {
   6497         uint8_t targetTypeId = map.keyAt(i);
   6498         const IdmapTypeMap& typeMap = map[i];
   6499         *typeData++ = htods(targetTypeId + 1);
   6500         *typeData++ = htods(typeMap.overlayTypeId);
   6501         *typeData++ = htods(typeMap.entryMap.size());
   6502         *typeData++ = htods(typeMap.entryOffset);
   6503 
   6504         const size_t entryCount = typeMap.entryMap.size();
   6505         uint32_t* entries = reinterpret_cast<uint32_t*>(typeData);
   6506         for (size_t j = 0; j < entryCount; j++) {
   6507             entries[j] = htodl(typeMap.entryMap[j]);
   6508         }
   6509         typeData += entryCount * 2;
   6510     }
   6511 
   6512     return NO_ERROR;
   6513 }
   6514 
   6515 bool ResTable::getIdmapInfo(const void* idmap, size_t sizeBytes,
   6516                             uint32_t* pVersion,
   6517                             uint32_t* pTargetCrc, uint32_t* pOverlayCrc,
   6518                             String8* pTargetPath, String8* pOverlayPath)
   6519 {
   6520     const uint32_t* map = (const uint32_t*)idmap;
   6521     if (!assertIdmapHeader(map, sizeBytes)) {
   6522         return false;
   6523     }
   6524     if (pVersion) {
   6525         *pVersion = dtohl(map[1]);
   6526     }
   6527     if (pTargetCrc) {
   6528         *pTargetCrc = dtohl(map[2]);
   6529     }
   6530     if (pOverlayCrc) {
   6531         *pOverlayCrc = dtohl(map[3]);
   6532     }
   6533     if (pTargetPath) {
   6534         pTargetPath->setTo(reinterpret_cast<const char*>(map + 4));
   6535     }
   6536     if (pOverlayPath) {
   6537         pOverlayPath->setTo(reinterpret_cast<const char*>(map + 4 + 256 / sizeof(uint32_t)));
   6538     }
   6539     return true;
   6540 }
   6541 
   6542 
   6543 #define CHAR16_TO_CSTR(c16, len) (String8(String16(c16,len)).string())
   6544 
   6545 #define CHAR16_ARRAY_EQ(constant, var, len) \
   6546         ((len == (sizeof(constant)/sizeof(constant[0]))) && (0 == memcmp((var), (constant), (len))))
   6547 
   6548 static void print_complex(uint32_t complex, bool isFraction)
   6549 {
   6550     const float MANTISSA_MULT =
   6551         1.0f / (1<<Res_value::COMPLEX_MANTISSA_SHIFT);
   6552     const float RADIX_MULTS[] = {
   6553         1.0f*MANTISSA_MULT, 1.0f/(1<<7)*MANTISSA_MULT,
   6554         1.0f/(1<<15)*MANTISSA_MULT, 1.0f/(1<<23)*MANTISSA_MULT
   6555     };
   6556 
   6557     float value = (complex&(Res_value::COMPLEX_MANTISSA_MASK
   6558                    <<Res_value::COMPLEX_MANTISSA_SHIFT))
   6559             * RADIX_MULTS[(complex>>Res_value::COMPLEX_RADIX_SHIFT)
   6560                             & Res_value::COMPLEX_RADIX_MASK];
   6561     printf("%f", value);
   6562 
   6563     if (!isFraction) {
   6564         switch ((complex>>Res_value::COMPLEX_UNIT_SHIFT)&Res_value::COMPLEX_UNIT_MASK) {
   6565             case Res_value::COMPLEX_UNIT_PX: printf("px"); break;
   6566             case Res_value::COMPLEX_UNIT_DIP: printf("dp"); break;
   6567             case Res_value::COMPLEX_UNIT_SP: printf("sp"); break;
   6568             case Res_value::COMPLEX_UNIT_PT: printf("pt"); break;
   6569             case Res_value::COMPLEX_UNIT_IN: printf("in"); break;
   6570             case Res_value::COMPLEX_UNIT_MM: printf("mm"); break;
   6571             default: printf(" (unknown unit)"); break;
   6572         }
   6573     } else {
   6574         switch ((complex>>Res_value::COMPLEX_UNIT_SHIFT)&Res_value::COMPLEX_UNIT_MASK) {
   6575             case Res_value::COMPLEX_UNIT_FRACTION: printf("%%"); break;
   6576             case Res_value::COMPLEX_UNIT_FRACTION_PARENT: printf("%%p"); break;
   6577             default: printf(" (unknown unit)"); break;
   6578         }
   6579     }
   6580 }
   6581 
   6582 // Normalize a string for output
   6583 String8 ResTable::normalizeForOutput( const char *input )
   6584 {
   6585     String8 ret;
   6586     char buff[2];
   6587     buff[1] = '\0';
   6588 
   6589     while (*input != '\0') {
   6590         switch (*input) {
   6591             // All interesting characters are in the ASCII zone, so we are making our own lives
   6592             // easier by scanning the string one byte at a time.
   6593         case '\\':
   6594             ret += "\\\\";
   6595             break;
   6596         case '\n':
   6597             ret += "\\n";
   6598             break;
   6599         case '"':
   6600             ret += "\\\"";
   6601             break;
   6602         default:
   6603             buff[0] = *input;
   6604             ret += buff;
   6605             break;
   6606         }
   6607 
   6608         input++;
   6609     }
   6610 
   6611     return ret;
   6612 }
   6613 
   6614 void ResTable::print_value(const Package* pkg, const Res_value& value) const
   6615 {
   6616     if (value.dataType == Res_value::TYPE_NULL) {
   6617         if (value.data == Res_value::DATA_NULL_UNDEFINED) {
   6618             printf("(null)\n");
   6619         } else if (value.data == Res_value::DATA_NULL_EMPTY) {
   6620             printf("(null empty)\n");
   6621         } else {
   6622             // This should never happen.
   6623             printf("(null) 0x%08x\n", value.data);
   6624         }
   6625     } else if (value.dataType == Res_value::TYPE_REFERENCE) {
   6626         printf("(reference) 0x%08x\n", value.data);
   6627     } else if (value.dataType == Res_value::TYPE_DYNAMIC_REFERENCE) {
   6628         printf("(dynamic reference) 0x%08x\n", value.data);
   6629     } else if (value.dataType == Res_value::TYPE_ATTRIBUTE) {
   6630         printf("(attribute) 0x%08x\n", value.data);
   6631     } else if (value.dataType == Res_value::TYPE_STRING) {
   6632         size_t len;
   6633         const char* str8 = pkg->header->values.string8At(
   6634                 value.data, &len);
   6635         if (str8 != NULL) {
   6636             printf("(string8) \"%s\"\n", normalizeForOutput(str8).string());
   6637         } else {
   6638             const char16_t* str16 = pkg->header->values.stringAt(
   6639                     value.data, &len);
   6640             if (str16 != NULL) {
   6641                 printf("(string16) \"%s\"\n",
   6642                     normalizeForOutput(String8(str16, len).string()).string());
   6643             } else {
   6644                 printf("(string) null\n");
   6645             }
   6646         }
   6647     } else if (value.dataType == Res_value::TYPE_FLOAT) {
   6648         printf("(float) %g\n", *(const float*)&value.data);
   6649     } else if (value.dataType == Res_value::TYPE_DIMENSION) {
   6650         printf("(dimension) ");
   6651         print_complex(value.data, false);
   6652         printf("\n");
   6653     } else if (value.dataType == Res_value::TYPE_FRACTION) {
   6654         printf("(fraction) ");
   6655         print_complex(value.data, true);
   6656         printf("\n");
   6657     } else if (value.dataType >= Res_value::TYPE_FIRST_COLOR_INT
   6658             || value.dataType <= Res_value::TYPE_LAST_COLOR_INT) {
   6659         printf("(color) #%08x\n", value.data);
   6660     } else if (value.dataType == Res_value::TYPE_INT_BOOLEAN) {
   6661         printf("(boolean) %s\n", value.data ? "true" : "false");
   6662     } else if (value.dataType >= Res_value::TYPE_FIRST_INT
   6663             || value.dataType <= Res_value::TYPE_LAST_INT) {
   6664         printf("(int) 0x%08x or %d\n", value.data, value.data);
   6665     } else {
   6666         printf("(unknown type) t=0x%02x d=0x%08x (s=0x%04x r=0x%02x)\n",
   6667                (int)value.dataType, (int)value.data,
   6668                (int)value.size, (int)value.res0);
   6669     }
   6670 }
   6671 
   6672 void ResTable::print(bool inclValues) const
   6673 {
   6674     if (mError != 0) {
   6675         printf("mError=0x%x (%s)\n", mError, strerror(mError));
   6676     }
   6677     size_t pgCount = mPackageGroups.size();
   6678     printf("Package Groups (%d)\n", (int)pgCount);
   6679     for (size_t pgIndex=0; pgIndex<pgCount; pgIndex++) {
   6680         const PackageGroup* pg = mPackageGroups[pgIndex];
   6681         printf("Package Group %d id=0x%02x packageCount=%d name=%s\n",
   6682                 (int)pgIndex, pg->id, (int)pg->packages.size(),
   6683                 String8(pg->name).string());
   6684 
   6685         const KeyedVector<String16, uint8_t>& refEntries = pg->dynamicRefTable.entries();
   6686         const size_t refEntryCount = refEntries.size();
   6687         if (refEntryCount > 0) {
   6688             printf("  DynamicRefTable entryCount=%d:\n", (int) refEntryCount);
   6689             for (size_t refIndex = 0; refIndex < refEntryCount; refIndex++) {
   6690                 printf("    0x%02x -> %s\n",
   6691                         refEntries.valueAt(refIndex),
   6692                         String8(refEntries.keyAt(refIndex)).string());
   6693             }
   6694             printf("\n");
   6695         }
   6696 
   6697         int packageId = pg->id;
   6698         size_t pkgCount = pg->packages.size();
   6699         for (size_t pkgIndex=0; pkgIndex<pkgCount; pkgIndex++) {
   6700             const Package* pkg = pg->packages[pkgIndex];
   6701             // Use a package's real ID, since the ID may have been assigned
   6702             // if this package is a shared library.
   6703             packageId = pkg->package->id;
   6704             char16_t tmpName[sizeof(pkg->package->name)/sizeof(pkg->package->name[0])];
   6705             strcpy16_dtoh(tmpName, pkg->package->name, sizeof(pkg->package->name)/sizeof(pkg->package->name[0]));
   6706             printf("  Package %d id=0x%02x name=%s\n", (int)pkgIndex,
   6707                     pkg->package->id, String8(tmpName).string());
   6708         }
   6709 
   6710         for (size_t typeIndex=0; typeIndex < pg->types.size(); typeIndex++) {
   6711             const TypeList& typeList = pg->types[typeIndex];
   6712             if (typeList.isEmpty()) {
   6713                 continue;
   6714             }
   6715             const Type* typeConfigs = typeList[0];
   6716             const size_t NTC = typeConfigs->configs.size();
   6717             printf("    type %d configCount=%d entryCount=%d\n",
   6718                    (int)typeIndex, (int)NTC, (int)typeConfigs->entryCount);
   6719             if (typeConfigs->typeSpecFlags != NULL) {
   6720                 for (size_t entryIndex=0; entryIndex<typeConfigs->entryCount; entryIndex++) {
   6721                     uint32_t resID = (0xff000000 & ((packageId)<<24))
   6722                                 | (0x00ff0000 & ((typeIndex+1)<<16))
   6723                                 | (0x0000ffff & (entryIndex));
   6724                     // Since we are creating resID without actually
   6725                     // iterating over them, we have no idea which is a
   6726                     // dynamic reference. We must check.
   6727                     if (packageId == 0) {
   6728                         pg->dynamicRefTable.lookupResourceId(&resID);
   6729                     }
   6730 
   6731                     resource_name resName;
   6732                     if (this->getResourceName(resID, true, &resName)) {
   6733                         String8 type8;
   6734                         String8 name8;
   6735                         if (resName.type8 != NULL) {
   6736                             type8 = String8(resName.type8, resName.typeLen);
   6737                         } else {
   6738                             type8 = String8(resName.type, resName.typeLen);
   6739                         }
   6740                         if (resName.name8 != NULL) {
   6741                             name8 = String8(resName.name8, resName.nameLen);
   6742                         } else {
   6743                             name8 = String8(resName.name, resName.nameLen);
   6744                         }
   6745                         printf("      spec resource 0x%08x %s:%s/%s: flags=0x%08x\n",
   6746                             resID,
   6747                             CHAR16_TO_CSTR(resName.package, resName.packageLen),
   6748                             type8.string(), name8.string(),
   6749                             dtohl(typeConfigs->typeSpecFlags[entryIndex]));
   6750                     } else {
   6751                         printf("      INVALID TYPE CONFIG FOR RESOURCE 0x%08x\n", resID);
   6752                     }
   6753                 }
   6754             }
   6755             for (size_t configIndex=0; configIndex<NTC; configIndex++) {
   6756                 const ResTable_type* type = typeConfigs->configs[configIndex];
   6757                 if ((((uint64_t)type)&0x3) != 0) {
   6758                     printf("      NON-INTEGER ResTable_type ADDRESS: %p\n", type);
   6759                     continue;
   6760                 }
   6761 
   6762                 // Always copy the config, as fields get added and we need to
   6763                 // set the defaults.
   6764                 ResTable_config thisConfig;
   6765                 thisConfig.copyFromDtoH(type->config);
   6766 
   6767                 String8 configStr = thisConfig.toString();
   6768                 printf("      config %s:\n", configStr.size() > 0
   6769                         ? configStr.string() : "(default)");
   6770                 size_t entryCount = dtohl(type->entryCount);
   6771                 uint32_t entriesStart = dtohl(type->entriesStart);
   6772                 if ((entriesStart&0x3) != 0) {
   6773                     printf("      NON-INTEGER ResTable_type entriesStart OFFSET: 0x%x\n", entriesStart);
   6774                     continue;
   6775                 }
   6776                 uint32_t typeSize = dtohl(type->header.size);
   6777                 if ((typeSize&0x3) != 0) {
   6778                     printf("      NON-INTEGER ResTable_type header.size: 0x%x\n", typeSize);
   6779                     continue;
   6780                 }
   6781                 for (size_t entryIndex=0; entryIndex<entryCount; entryIndex++) {
   6782                     const uint32_t* const eindex = (const uint32_t*)
   6783                         (((const uint8_t*)type) + dtohs(type->header.headerSize));
   6784 
   6785                     uint32_t thisOffset = dtohl(eindex[entryIndex]);
   6786                     if (thisOffset == ResTable_type::NO_ENTRY) {
   6787                         continue;
   6788                     }
   6789 
   6790                     uint32_t resID = (0xff000000 & ((packageId)<<24))
   6791                                 | (0x00ff0000 & ((typeIndex+1)<<16))
   6792                                 | (0x0000ffff & (entryIndex));
   6793                     if (packageId == 0) {
   6794                         pg->dynamicRefTable.lookupResourceId(&resID);
   6795                     }
   6796                     resource_name resName;
   6797                     if (this->getResourceName(resID, true, &resName)) {
   6798                         String8 type8;
   6799                         String8 name8;
   6800                         if (resName.type8 != NULL) {
   6801                             type8 = String8(resName.type8, resName.typeLen);
   6802                         } else {
   6803                             type8 = String8(resName.type, resName.typeLen);
   6804                         }
   6805                         if (resName.name8 != NULL) {
   6806                             name8 = String8(resName.name8, resName.nameLen);
   6807                         } else {
   6808                             name8 = String8(resName.name, resName.nameLen);
   6809                         }
   6810                         printf("        resource 0x%08x %s:%s/%s: ", resID,
   6811                                 CHAR16_TO_CSTR(resName.package, resName.packageLen),
   6812                                 type8.string(), name8.string());
   6813                     } else {
   6814                         printf("        INVALID RESOURCE 0x%08x: ", resID);
   6815                     }
   6816                     if ((thisOffset&0x3) != 0) {
   6817                         printf("NON-INTEGER OFFSET: 0x%x\n", thisOffset);
   6818                         continue;
   6819                     }
   6820                     if ((thisOffset+sizeof(ResTable_entry)) > typeSize) {
   6821                         printf("OFFSET OUT OF BOUNDS: 0x%x+0x%x (size is 0x%x)\n",
   6822                                entriesStart, thisOffset, typeSize);
   6823                         continue;
   6824                     }
   6825 
   6826                     const ResTable_entry* ent = (const ResTable_entry*)
   6827                         (((const uint8_t*)type) + entriesStart + thisOffset);
   6828                     if (((entriesStart + thisOffset)&0x3) != 0) {
   6829                         printf("NON-INTEGER ResTable_entry OFFSET: 0x%x\n",
   6830                              (entriesStart + thisOffset));
   6831                         continue;
   6832                     }
   6833 
   6834                     uintptr_t esize = dtohs(ent->size);
   6835                     if ((esize&0x3) != 0) {
   6836                         printf("NON-INTEGER ResTable_entry SIZE: %p\n", (void *)esize);
   6837                         continue;
   6838                     }
   6839                     if ((thisOffset+esize) > typeSize) {
   6840                         printf("ResTable_entry OUT OF BOUNDS: 0x%x+0x%x+%p (size is 0x%x)\n",
   6841                                entriesStart, thisOffset, (void *)esize, typeSize);
   6842                         continue;
   6843                     }
   6844 
   6845                     const Res_value* valuePtr = NULL;
   6846                     const ResTable_map_entry* bagPtr = NULL;
   6847                     Res_value value;
   6848                     if ((dtohs(ent->flags)&ResTable_entry::FLAG_COMPLEX) != 0) {
   6849                         printf("<bag>");
   6850                         bagPtr = (const ResTable_map_entry*)ent;
   6851                     } else {
   6852                         valuePtr = (const Res_value*)
   6853                             (((const uint8_t*)ent) + esize);
   6854                         value.copyFrom_dtoh(*valuePtr);
   6855                         printf("t=0x%02x d=0x%08x (s=0x%04x r=0x%02x)",
   6856                                (int)value.dataType, (int)value.data,
   6857                                (int)value.size, (int)value.res0);
   6858                     }
   6859 
   6860                     if ((dtohs(ent->flags)&ResTable_entry::FLAG_PUBLIC) != 0) {
   6861                         printf(" (PUBLIC)");
   6862                     }
   6863                     printf("\n");
   6864 
   6865                     if (inclValues) {
   6866                         if (valuePtr != NULL) {
   6867                             printf("          ");
   6868                             print_value(typeConfigs->package, value);
   6869                         } else if (bagPtr != NULL) {
   6870                             const int N = dtohl(bagPtr->count);
   6871                             const uint8_t* baseMapPtr = (const uint8_t*)ent;
   6872                             size_t mapOffset = esize;
   6873                             const ResTable_map* mapPtr = (ResTable_map*)(baseMapPtr+mapOffset);
   6874                             const uint32_t parent = dtohl(bagPtr->parent.ident);
   6875                             uint32_t resolvedParent = parent;
   6876                             if (Res_GETPACKAGE(resolvedParent) + 1 == 0) {
   6877                                 status_t err = pg->dynamicRefTable.lookupResourceId(&resolvedParent);
   6878                                 if (err != NO_ERROR) {
   6879                                     resolvedParent = 0;
   6880                                 }
   6881                             }
   6882                             printf("          Parent=0x%08x(Resolved=0x%08x), Count=%d\n",
   6883                                     parent, resolvedParent, N);
   6884                             for (int i=0; i<N && mapOffset < (typeSize-sizeof(ResTable_map)); i++) {
   6885                                 printf("          #%i (Key=0x%08x): ",
   6886                                     i, dtohl(mapPtr->name.ident));
   6887                                 value.copyFrom_dtoh(mapPtr->value);
   6888                                 print_value(typeConfigs->package, value);
   6889                                 const size_t size = dtohs(mapPtr->value.size);
   6890                                 mapOffset += size + sizeof(*mapPtr)-sizeof(mapPtr->value);
   6891                                 mapPtr = (ResTable_map*)(baseMapPtr+mapOffset);
   6892                             }
   6893                         }
   6894                     }
   6895                 }
   6896             }
   6897         }
   6898     }
   6899 }
   6900 
   6901 }   // namespace android
   6902