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