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
50namespace 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
67static const bool kDebugStringPoolNoisy = false;
68static const bool kDebugXMLNoisy = false;
69static const bool kDebugTableNoisy = false;
70static const bool kDebugTableGetEntry = false;
71static const bool kDebugTableSuperNoisy = false;
72static const bool kDebugLoadTableNoisy = false;
73static const bool kDebugLoadTableSuperNoisy = false;
74static const bool kDebugTableTheme = false;
75static const bool kDebugResXMLTree = false;
76static 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.
83inline int isspace16(char16_t c) {
84    return (c < 0x0080 && isspace(c));
85}
86
87template<typename T>
88inline 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.
95static 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
106static 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
137static 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
143inline 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
151void 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
171void 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
191size_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
203void* 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
213void 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
230static 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
259class IdmapEntries {
260public:
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
350private:
351    const uint16_t* mData;
352};
353
354status_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
406Res_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
420ResStringPool::ResStringPool()
421    : mError(NO_INIT), mOwnedData(NULL), mHeader(NULL), mCache(NULL)
422{
423}
424
425ResStringPool::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
431ResStringPool::~ResStringPool()
432{
433    uninit();
434}
435
436void 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
452status_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
629status_t ResStringPool::getError() const
630{
631    return mError;
632}
633
634void 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 */
663static inline size_t
664decodeLength(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 */
685static inline size_t
686decodeLength(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
697const 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
797const 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
824const 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
839const ResStringPool_span* ResStringPool::styleAt(const ResStringPool_ref& ref) const
840{
841    return styleAt(ref.index);
842}
843
844const 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
859ssize_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
987size_t ResStringPool::size() const
988{
989    return (mError == NO_ERROR) ? mHeader->stringCount : 0;
990}
991
992size_t ResStringPool::styleCount() const
993{
994    return (mError == NO_ERROR) ? mHeader->styleCount : 0;
995}
996
997size_t ResStringPool::bytes() const
998{
999    return (mError == NO_ERROR) ? mHeader->header.size : 0;
1000}
1001
1002bool ResStringPool::isSorted() const
1003{
1004    return (mHeader->flags&ResStringPool_header::SORTED_FLAG)!=0;
1005}
1006
1007bool ResStringPool::isUTF8() const
1008{
1009    return (mHeader->flags&ResStringPool_header::UTF8_FLAG)!=0;
1010}
1011
1012// --------------------------------------------------------------------
1013// --------------------------------------------------------------------
1014// --------------------------------------------------------------------
1015
1016ResXMLParser::ResXMLParser(const ResXMLTree& tree)
1017    : mTree(tree), mEventCode(BAD_DOCUMENT)
1018{
1019}
1020
1021void ResXMLParser::restart()
1022{
1023    mCurNode = NULL;
1024    mEventCode = mTree.mError == NO_ERROR ? START_DOCUMENT : BAD_DOCUMENT;
1025}
1026const ResStringPool& ResXMLParser::getStrings() const
1027{
1028    return mTree.mStrings;
1029}
1030
1031ResXMLParser::event_code_t ResXMLParser::getEventType() const
1032{
1033    return mEventCode;
1034}
1035
1036ResXMLParser::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
1048int32_t ResXMLParser::getCommentID() const
1049{
1050    return mCurNode != NULL ? dtohl(mCurNode->comment.index) : -1;
1051}
1052
1053const 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
1059uint32_t ResXMLParser::getLineNumber() const
1060{
1061    return mCurNode != NULL ? dtohl(mCurNode->lineNumber) : -1;
1062}
1063
1064int32_t ResXMLParser::getTextID() const
1065{
1066    if (mEventCode == TEXT) {
1067        return dtohl(((const ResXMLTree_cdataExt*)mCurExt)->data.index);
1068    }
1069    return -1;
1070}
1071
1072const 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
1078ssize_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
1087int32_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
1095const 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
1102int32_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
1110const 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
1117int32_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
1128const 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
1134int32_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
1145const 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
1151size_t ResXMLParser::getAttributeCount() const
1152{
1153    if (mEventCode == START_TAG) {
1154        return dtohs(((const ResXMLTree_attrExt*)mCurExt)->attributeCount);
1155    }
1156    return 0;
1157}
1158
1159int32_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
1174const 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
1184const 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
1194int32_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
1209const 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
1219const 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
1229uint32_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
1242int32_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
1257const 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
1266int32_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
1288int32_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
1311ssize_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
1331ssize_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
1339ssize_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
1427ssize_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
1436ssize_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
1445ssize_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
1454ResXMLParser::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
1519void ResXMLParser::getPosition(ResXMLParser::ResXMLPosition* pos) const
1520{
1521    pos->eventCode = mEventCode;
1522    pos->curNode = mCurNode;
1523    pos->curExt = mCurExt;
1524}
1525
1526void ResXMLParser::setPosition(const ResXMLParser::ResXMLPosition& pos)
1527{
1528    mEventCode = pos.eventCode;
1529    mCurNode = pos.curNode;
1530    mCurExt = pos.curExt;
1531}
1532
1533// --------------------------------------------------------------------
1534
1535static volatile int32_t gCount = 0;
1536
1537ResXMLTree::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
1548ResXMLTree::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
1559ResXMLTree::~ResXMLTree()
1560{
1561    if (kDebugResXMLTree) {
1562        ALOGI("Destroying ResXMLTree in %p #%d\n", this, android_atomic_dec(&gCount)-1);
1563    }
1564    uninit();
1565}
1566
1567status_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
1659done:
1660    restart();
1661    return mError;
1662}
1663
1664status_t ResXMLTree::getError() const
1665{
1666    return mError;
1667}
1668
1669void ResXMLTree::uninit()
1670{
1671    mError = NO_INIT;
1672    mStrings.uninit();
1673    if (mOwnedData) {
1674        free(mOwnedData);
1675        mOwnedData = NULL;
1676    }
1677    restart();
1678}
1679
1680status_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
1760void 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
1818void ResTable_config::packLanguage(const char* language) {
1819    packLanguageOrRegion(language, 'a', this->language);
1820}
1821
1822void ResTable_config::packRegion(const char* region) {
1823    packLanguageOrRegion(region, '0', this->country);
1824}
1825
1826size_t ResTable_config::unpackLanguage(char language[4]) const {
1827    return unpackLanguageOrRegion(this->language, 'a', language);
1828}
1829
1830size_t ResTable_config::unpackRegion(char region[4]) const {
1831    return unpackLanguageOrRegion(this->country, '0', region);
1832}
1833
1834
1835void 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
1850void 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
1887int 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
1912int 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
1973int 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
1999int 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
2030bool 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
2173bool 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
2255bool 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
2507bool 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
2685void 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
2737void 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
2809void 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
2833String8 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
3117struct 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
3140struct 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
3151struct 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
3165struct 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.
3189struct 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
3304ResTable::Theme::Theme(const ResTable& table)
3305    : mTable(table)
3306    , mTypeSpecFlags(0)
3307{
3308    memset(mPackages, 0, sizeof(mPackages));
3309}
3310
3311ResTable::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
3321void 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
3332ResTable::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
3351status_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
3450status_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
3495status_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
3519ssize_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
3583ssize_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
3605uint32_t ResTable::Theme::getChangingConfigurations() const
3606{
3607    return mTypeSpecFlags;
3608}
3609
3610void 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
3633ResTable::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
3643ResTable::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
3655ResTable::~ResTable()
3656{
3657    if (kDebugTableSuperNoisy) {
3658        ALOGI("Destroying ResTable in %p\n", this);
3659    }
3660    uninit();
3661}
3662
3663inline ssize_t ResTable::getResourcePackageIndex(uint32_t resID) const
3664{
3665    return ((ssize_t)mPackageMap[Res_GETPACKAGE(resID)+1])-1;
3666}
3667
3668status_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
3672status_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
3677status_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
3688status_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
3712status_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
3746status_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
3763status_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
3897status_t ResTable::getError() const
3898{
3899    return mError;
3900}
3901
3902void 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
3925bool 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
3989ssize_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
4083ssize_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
4115const 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
4129ssize_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
4140void ResTable::unlockBag(const bag_entry* /*bag*/) const
4141{
4142    //printf("<<< unlockBag %p\n", this);
4143    mLock.unlock();
4144}
4145
4146void ResTable::lock() const
4147{
4148    mLock.lock();
4149}
4150
4151void ResTable::unlock() const
4152{
4153    mLock.unlock();
4154}
4155
4156ssize_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
4426void 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
4480void ResTable::getParameters(ResTable_config* params) const
4481{
4482    mLock.lock();
4483    *params = mParams;
4484    mLock.unlock();
4485}
4486
4487struct id_name_map {
4488    uint32_t id;
4489    size_t len;
4490    char16_t name[6];
4491};
4492
4493const 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
4506uint32_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;
4536nope:
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
4661uint32_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
4701bool 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
4781static 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
4794struct unit_entry
4795{
4796    const char* name;
4797    size_t len;
4798    uint8_t type;
4799    uint32_t unit;
4800    float scale;
4801};
4802
4803static 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
4816static 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
4849bool 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
4938bool ResTable::stringToInt(const char16_t* s, size_t len, Res_value* outValue)
4939{
4940    return U16StringToInt(s, len, outValue);
4941}
4942
4943bool 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
5038bool 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
5607bool 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.