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