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