ResourceTypes.cpp revision 70bf06986a90c21137fc4836aa0e56d68a2ab588
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            case ResTable_config::UI_MODE_TYPE_WATCH:
2521                res.append("watch");
2522                break;
2523            default:
2524                res.appendFormat("uiModeType=%d",
2525                        dtohs(screenLayout&ResTable_config::MASK_UI_MODE_TYPE));
2526                break;
2527        }
2528    }
2529    if ((uiMode&MASK_UI_MODE_NIGHT) != 0) {
2530        if (res.size() > 0) res.append("-");
2531        switch (uiMode&ResTable_config::MASK_UI_MODE_NIGHT) {
2532            case ResTable_config::UI_MODE_NIGHT_NO:
2533                res.append("notnight");
2534                break;
2535            case ResTable_config::UI_MODE_NIGHT_YES:
2536                res.append("night");
2537                break;
2538            default:
2539                res.appendFormat("uiModeNight=%d",
2540                        dtohs(uiMode&MASK_UI_MODE_NIGHT));
2541                break;
2542        }
2543    }
2544    if (density != DENSITY_DEFAULT) {
2545        if (res.size() > 0) res.append("-");
2546        switch (density) {
2547            case ResTable_config::DENSITY_LOW:
2548                res.append("ldpi");
2549                break;
2550            case ResTable_config::DENSITY_MEDIUM:
2551                res.append("mdpi");
2552                break;
2553            case ResTable_config::DENSITY_TV:
2554                res.append("tvdpi");
2555                break;
2556            case ResTable_config::DENSITY_HIGH:
2557                res.append("hdpi");
2558                break;
2559            case ResTable_config::DENSITY_XHIGH:
2560                res.append("xhdpi");
2561                break;
2562            case ResTable_config::DENSITY_XXHIGH:
2563                res.append("xxhdpi");
2564                break;
2565            case ResTable_config::DENSITY_NONE:
2566                res.append("nodpi");
2567                break;
2568            default:
2569                res.appendFormat("%ddpi", dtohs(density));
2570                break;
2571        }
2572    }
2573    if (touchscreen != TOUCHSCREEN_ANY) {
2574        if (res.size() > 0) res.append("-");
2575        switch (touchscreen) {
2576            case ResTable_config::TOUCHSCREEN_NOTOUCH:
2577                res.append("notouch");
2578                break;
2579            case ResTable_config::TOUCHSCREEN_FINGER:
2580                res.append("finger");
2581                break;
2582            case ResTable_config::TOUCHSCREEN_STYLUS:
2583                res.append("stylus");
2584                break;
2585            default:
2586                res.appendFormat("touchscreen=%d", dtohs(touchscreen));
2587                break;
2588        }
2589    }
2590    if (keyboard != KEYBOARD_ANY) {
2591        if (res.size() > 0) res.append("-");
2592        switch (keyboard) {
2593            case ResTable_config::KEYBOARD_NOKEYS:
2594                res.append("nokeys");
2595                break;
2596            case ResTable_config::KEYBOARD_QWERTY:
2597                res.append("qwerty");
2598                break;
2599            case ResTable_config::KEYBOARD_12KEY:
2600                res.append("12key");
2601                break;
2602            default:
2603                res.appendFormat("keyboard=%d", dtohs(keyboard));
2604                break;
2605        }
2606    }
2607    if ((inputFlags&MASK_KEYSHIDDEN) != 0) {
2608        if (res.size() > 0) res.append("-");
2609        switch (inputFlags&MASK_KEYSHIDDEN) {
2610            case ResTable_config::KEYSHIDDEN_NO:
2611                res.append("keysexposed");
2612                break;
2613            case ResTable_config::KEYSHIDDEN_YES:
2614                res.append("keyshidden");
2615                break;
2616            case ResTable_config::KEYSHIDDEN_SOFT:
2617                res.append("keyssoft");
2618                break;
2619        }
2620    }
2621    if (navigation != NAVIGATION_ANY) {
2622        if (res.size() > 0) res.append("-");
2623        switch (navigation) {
2624            case ResTable_config::NAVIGATION_NONAV:
2625                res.append("nonav");
2626                break;
2627            case ResTable_config::NAVIGATION_DPAD:
2628                res.append("dpad");
2629                break;
2630            case ResTable_config::NAVIGATION_TRACKBALL:
2631                res.append("trackball");
2632                break;
2633            case ResTable_config::NAVIGATION_WHEEL:
2634                res.append("wheel");
2635                break;
2636            default:
2637                res.appendFormat("navigation=%d", dtohs(navigation));
2638                break;
2639        }
2640    }
2641    if ((inputFlags&MASK_NAVHIDDEN) != 0) {
2642        if (res.size() > 0) res.append("-");
2643        switch (inputFlags&MASK_NAVHIDDEN) {
2644            case ResTable_config::NAVHIDDEN_NO:
2645                res.append("navsexposed");
2646                break;
2647            case ResTable_config::NAVHIDDEN_YES:
2648                res.append("navhidden");
2649                break;
2650            default:
2651                res.appendFormat("inputFlagsNavHidden=%d",
2652                        dtohs(inputFlags&MASK_NAVHIDDEN));
2653                break;
2654        }
2655    }
2656    if (screenSize != 0) {
2657        if (res.size() > 0) res.append("-");
2658        res.appendFormat("%dx%d", dtohs(screenWidth), dtohs(screenHeight));
2659    }
2660    if (version != 0) {
2661        if (res.size() > 0) res.append("-");
2662        res.appendFormat("v%d", dtohs(sdkVersion));
2663        if (minorVersion != 0) {
2664            res.appendFormat(".%d", dtohs(minorVersion));
2665        }
2666    }
2667
2668    return res;
2669}
2670
2671// --------------------------------------------------------------------
2672// --------------------------------------------------------------------
2673// --------------------------------------------------------------------
2674
2675struct ResTable::Header
2676{
2677    Header(ResTable* _owner) : owner(_owner), ownedData(NULL), header(NULL),
2678        resourceIDMap(NULL), resourceIDMapSize(0) { }
2679
2680    ~Header()
2681    {
2682        free(resourceIDMap);
2683    }
2684
2685    ResTable* const                 owner;
2686    void*                           ownedData;
2687    const ResTable_header*          header;
2688    size_t                          size;
2689    const uint8_t*                  dataEnd;
2690    size_t                          index;
2691    int32_t                         cookie;
2692
2693    ResStringPool                   values;
2694    uint32_t*                       resourceIDMap;
2695    size_t                          resourceIDMapSize;
2696};
2697
2698struct ResTable::Type
2699{
2700    Type(const Header* _header, const Package* _package, size_t count)
2701        : header(_header), package(_package), entryCount(count),
2702          typeSpec(NULL), typeSpecFlags(NULL) { }
2703    const Header* const             header;
2704    const Package* const            package;
2705    const size_t                    entryCount;
2706    const ResTable_typeSpec*        typeSpec;
2707    const uint32_t*                 typeSpecFlags;
2708    Vector<const ResTable_type*>    configs;
2709};
2710
2711struct ResTable::Package
2712{
2713    Package(ResTable* _owner, const Header* _header, const ResTable_package* _package)
2714        : owner(_owner), header(_header), package(_package) { }
2715    ~Package()
2716    {
2717        size_t i = types.size();
2718        while (i > 0) {
2719            i--;
2720            delete types[i];
2721        }
2722    }
2723
2724    ResTable* const                 owner;
2725    const Header* const             header;
2726    const ResTable_package* const   package;
2727    Vector<Type*>                   types;
2728
2729    ResStringPool                   typeStrings;
2730    ResStringPool                   keyStrings;
2731
2732    const Type* getType(size_t idx) const {
2733        return idx < types.size() ? types[idx] : NULL;
2734    }
2735};
2736
2737// A group of objects describing a particular resource package.
2738// The first in 'package' is always the root object (from the resource
2739// table that defined the package); the ones after are skins on top of it.
2740struct ResTable::PackageGroup
2741{
2742    PackageGroup(ResTable* _owner, const String16& _name, uint32_t _id)
2743        : owner(_owner), name(_name), id(_id), typeCount(0), bags(NULL) { }
2744    ~PackageGroup() {
2745        clearBagCache();
2746        const size_t N = packages.size();
2747        for (size_t i=0; i<N; i++) {
2748            Package* pkg = packages[i];
2749            if (pkg->owner == owner) {
2750                delete pkg;
2751            }
2752        }
2753    }
2754
2755    void clearBagCache() {
2756        if (bags) {
2757            TABLE_NOISY(printf("bags=%p\n", bags));
2758            Package* pkg = packages[0];
2759            TABLE_NOISY(printf("typeCount=%x\n", typeCount));
2760            for (size_t i=0; i<typeCount; i++) {
2761                TABLE_NOISY(printf("type=%d\n", i));
2762                const Type* type = pkg->getType(i);
2763                if (type != NULL) {
2764                    bag_set** typeBags = bags[i];
2765                    TABLE_NOISY(printf("typeBags=%p\n", typeBags));
2766                    if (typeBags) {
2767                        TABLE_NOISY(printf("type->entryCount=%x\n", type->entryCount));
2768                        const size_t N = type->entryCount;
2769                        for (size_t j=0; j<N; j++) {
2770                            if (typeBags[j] && typeBags[j] != (bag_set*)0xFFFFFFFF)
2771                                free(typeBags[j]);
2772                        }
2773                        free(typeBags);
2774                    }
2775                }
2776            }
2777            free(bags);
2778            bags = NULL;
2779        }
2780    }
2781
2782    ResTable* const                 owner;
2783    String16 const                  name;
2784    uint32_t const                  id;
2785    Vector<Package*>                packages;
2786
2787    // This is for finding typeStrings and other common package stuff.
2788    Package*                        basePackage;
2789
2790    // For quick access.
2791    size_t                          typeCount;
2792
2793    // Computed attribute bags, first indexed by the type and second
2794    // by the entry in that type.
2795    bag_set***                      bags;
2796};
2797
2798struct ResTable::bag_set
2799{
2800    size_t numAttrs;    // number in array
2801    size_t availAttrs;  // total space in array
2802    uint32_t typeSpecFlags;
2803    // Followed by 'numAttr' bag_entry structures.
2804};
2805
2806ResTable::Theme::Theme(const ResTable& table)
2807    : mTable(table)
2808{
2809    memset(mPackages, 0, sizeof(mPackages));
2810}
2811
2812ResTable::Theme::~Theme()
2813{
2814    for (size_t i=0; i<Res_MAXPACKAGE; i++) {
2815        package_info* pi = mPackages[i];
2816        if (pi != NULL) {
2817            free_package(pi);
2818        }
2819    }
2820}
2821
2822void ResTable::Theme::free_package(package_info* pi)
2823{
2824    for (size_t j=0; j<pi->numTypes; j++) {
2825        theme_entry* te = pi->types[j].entries;
2826        if (te != NULL) {
2827            free(te);
2828        }
2829    }
2830    free(pi);
2831}
2832
2833ResTable::Theme::package_info* ResTable::Theme::copy_package(package_info* pi)
2834{
2835    package_info* newpi = (package_info*)malloc(
2836        sizeof(package_info) + (pi->numTypes*sizeof(type_info)));
2837    newpi->numTypes = pi->numTypes;
2838    for (size_t j=0; j<newpi->numTypes; j++) {
2839        size_t cnt = pi->types[j].numEntries;
2840        newpi->types[j].numEntries = cnt;
2841        theme_entry* te = pi->types[j].entries;
2842        if (te != NULL) {
2843            theme_entry* newte = (theme_entry*)malloc(cnt*sizeof(theme_entry));
2844            newpi->types[j].entries = newte;
2845            memcpy(newte, te, cnt*sizeof(theme_entry));
2846        } else {
2847            newpi->types[j].entries = NULL;
2848        }
2849    }
2850    return newpi;
2851}
2852
2853status_t ResTable::Theme::applyStyle(uint32_t resID, bool force)
2854{
2855    const bag_entry* bag;
2856    uint32_t bagTypeSpecFlags = 0;
2857    mTable.lock();
2858    const ssize_t N = mTable.getBagLocked(resID, &bag, &bagTypeSpecFlags);
2859    TABLE_NOISY(ALOGV("Applying style 0x%08x to theme %p, count=%d", resID, this, N));
2860    if (N < 0) {
2861        mTable.unlock();
2862        return N;
2863    }
2864
2865    uint32_t curPackage = 0xffffffff;
2866    ssize_t curPackageIndex = 0;
2867    package_info* curPI = NULL;
2868    uint32_t curType = 0xffffffff;
2869    size_t numEntries = 0;
2870    theme_entry* curEntries = NULL;
2871
2872    const bag_entry* end = bag + N;
2873    while (bag < end) {
2874        const uint32_t attrRes = bag->map.name.ident;
2875        const uint32_t p = Res_GETPACKAGE(attrRes);
2876        const uint32_t t = Res_GETTYPE(attrRes);
2877        const uint32_t e = Res_GETENTRY(attrRes);
2878
2879        if (curPackage != p) {
2880            const ssize_t pidx = mTable.getResourcePackageIndex(attrRes);
2881            if (pidx < 0) {
2882                ALOGE("Style contains key with bad package: 0x%08x\n", attrRes);
2883                bag++;
2884                continue;
2885            }
2886            curPackage = p;
2887            curPackageIndex = pidx;
2888            curPI = mPackages[pidx];
2889            if (curPI == NULL) {
2890                PackageGroup* const grp = mTable.mPackageGroups[pidx];
2891                int cnt = grp->typeCount;
2892                curPI = (package_info*)malloc(
2893                    sizeof(package_info) + (cnt*sizeof(type_info)));
2894                curPI->numTypes = cnt;
2895                memset(curPI->types, 0, cnt*sizeof(type_info));
2896                mPackages[pidx] = curPI;
2897            }
2898            curType = 0xffffffff;
2899        }
2900        if (curType != t) {
2901            if (t >= curPI->numTypes) {
2902                ALOGE("Style contains key with bad type: 0x%08x\n", attrRes);
2903                bag++;
2904                continue;
2905            }
2906            curType = t;
2907            curEntries = curPI->types[t].entries;
2908            if (curEntries == NULL) {
2909                PackageGroup* const grp = mTable.mPackageGroups[curPackageIndex];
2910                const Type* type = grp->packages[0]->getType(t);
2911                int cnt = type != NULL ? type->entryCount : 0;
2912                curEntries = (theme_entry*)malloc(cnt*sizeof(theme_entry));
2913                memset(curEntries, Res_value::TYPE_NULL, cnt*sizeof(theme_entry));
2914                curPI->types[t].numEntries = cnt;
2915                curPI->types[t].entries = curEntries;
2916            }
2917            numEntries = curPI->types[t].numEntries;
2918        }
2919        if (e >= numEntries) {
2920            ALOGE("Style contains key with bad entry: 0x%08x\n", attrRes);
2921            bag++;
2922            continue;
2923        }
2924        theme_entry* curEntry = curEntries + e;
2925        TABLE_NOISY(ALOGV("Attr 0x%08x: type=0x%x, data=0x%08x; curType=0x%x",
2926                   attrRes, bag->map.value.dataType, bag->map.value.data,
2927             curEntry->value.dataType));
2928        if (force || curEntry->value.dataType == Res_value::TYPE_NULL) {
2929            curEntry->stringBlock = bag->stringBlock;
2930            curEntry->typeSpecFlags |= bagTypeSpecFlags;
2931            curEntry->value = bag->map.value;
2932        }
2933
2934        bag++;
2935    }
2936
2937    mTable.unlock();
2938
2939    //ALOGI("Applying style 0x%08x (force=%d)  theme %p...\n", resID, force, this);
2940    //dumpToLog();
2941
2942    return NO_ERROR;
2943}
2944
2945status_t ResTable::Theme::setTo(const Theme& other)
2946{
2947    //ALOGI("Setting theme %p from theme %p...\n", this, &other);
2948    //dumpToLog();
2949    //other.dumpToLog();
2950
2951    if (&mTable == &other.mTable) {
2952        for (size_t i=0; i<Res_MAXPACKAGE; i++) {
2953            if (mPackages[i] != NULL) {
2954                free_package(mPackages[i]);
2955            }
2956            if (other.mPackages[i] != NULL) {
2957                mPackages[i] = copy_package(other.mPackages[i]);
2958            } else {
2959                mPackages[i] = NULL;
2960            }
2961        }
2962    } else {
2963        // @todo: need to really implement this, not just copy
2964        // the system package (which is still wrong because it isn't
2965        // fixing up resource references).
2966        for (size_t i=0; i<Res_MAXPACKAGE; i++) {
2967            if (mPackages[i] != NULL) {
2968                free_package(mPackages[i]);
2969            }
2970            if (i == 0 && other.mPackages[i] != NULL) {
2971                mPackages[i] = copy_package(other.mPackages[i]);
2972            } else {
2973                mPackages[i] = NULL;
2974            }
2975        }
2976    }
2977
2978    //ALOGI("Final theme:");
2979    //dumpToLog();
2980
2981    return NO_ERROR;
2982}
2983
2984ssize_t ResTable::Theme::getAttribute(uint32_t resID, Res_value* outValue,
2985        uint32_t* outTypeSpecFlags) const
2986{
2987    int cnt = 20;
2988
2989    if (outTypeSpecFlags != NULL) *outTypeSpecFlags = 0;
2990
2991    do {
2992        const ssize_t p = mTable.getResourcePackageIndex(resID);
2993        const uint32_t t = Res_GETTYPE(resID);
2994        const uint32_t e = Res_GETENTRY(resID);
2995
2996        TABLE_THEME(ALOGI("Looking up attr 0x%08x in theme %p", resID, this));
2997
2998        if (p >= 0) {
2999            const package_info* const pi = mPackages[p];
3000            TABLE_THEME(ALOGI("Found package: %p", pi));
3001            if (pi != NULL) {
3002                TABLE_THEME(ALOGI("Desired type index is %ld in avail %d", t, pi->numTypes));
3003                if (t < pi->numTypes) {
3004                    const type_info& ti = pi->types[t];
3005                    TABLE_THEME(ALOGI("Desired entry index is %ld in avail %d", e, ti.numEntries));
3006                    if (e < ti.numEntries) {
3007                        const theme_entry& te = ti.entries[e];
3008                        if (outTypeSpecFlags != NULL) {
3009                            *outTypeSpecFlags |= te.typeSpecFlags;
3010                        }
3011                        TABLE_THEME(ALOGI("Theme value: type=0x%x, data=0x%08x",
3012                                te.value.dataType, te.value.data));
3013                        const uint8_t type = te.value.dataType;
3014                        if (type == Res_value::TYPE_ATTRIBUTE) {
3015                            if (cnt > 0) {
3016                                cnt--;
3017                                resID = te.value.data;
3018                                continue;
3019                            }
3020                            ALOGW("Too many attribute references, stopped at: 0x%08x\n", resID);
3021                            return BAD_INDEX;
3022                        } else if (type != Res_value::TYPE_NULL) {
3023                            *outValue = te.value;
3024                            return te.stringBlock;
3025                        }
3026                        return BAD_INDEX;
3027                    }
3028                }
3029            }
3030        }
3031        break;
3032
3033    } while (true);
3034
3035    return BAD_INDEX;
3036}
3037
3038ssize_t ResTable::Theme::resolveAttributeReference(Res_value* inOutValue,
3039        ssize_t blockIndex, uint32_t* outLastRef,
3040        uint32_t* inoutTypeSpecFlags, ResTable_config* inoutConfig) const
3041{
3042    //printf("Resolving type=0x%x\n", inOutValue->dataType);
3043    if (inOutValue->dataType == Res_value::TYPE_ATTRIBUTE) {
3044        uint32_t newTypeSpecFlags;
3045        blockIndex = getAttribute(inOutValue->data, inOutValue, &newTypeSpecFlags);
3046        TABLE_THEME(ALOGI("Resolving attr reference: blockIndex=%d, type=0x%x, data=%p\n",
3047             (int)blockIndex, (int)inOutValue->dataType, (void*)inOutValue->data));
3048        if (inoutTypeSpecFlags != NULL) *inoutTypeSpecFlags |= newTypeSpecFlags;
3049        //printf("Retrieved attribute new type=0x%x\n", inOutValue->dataType);
3050        if (blockIndex < 0) {
3051            return blockIndex;
3052        }
3053    }
3054    return mTable.resolveReference(inOutValue, blockIndex, outLastRef,
3055            inoutTypeSpecFlags, inoutConfig);
3056}
3057
3058void ResTable::Theme::dumpToLog() const
3059{
3060    ALOGI("Theme %p:\n", this);
3061    for (size_t i=0; i<Res_MAXPACKAGE; i++) {
3062        package_info* pi = mPackages[i];
3063        if (pi == NULL) continue;
3064
3065        ALOGI("  Package #0x%02x:\n", (int)(i+1));
3066        for (size_t j=0; j<pi->numTypes; j++) {
3067            type_info& ti = pi->types[j];
3068            if (ti.numEntries == 0) continue;
3069
3070            ALOGI("    Type #0x%02x:\n", (int)(j+1));
3071            for (size_t k=0; k<ti.numEntries; k++) {
3072                theme_entry& te = ti.entries[k];
3073                if (te.value.dataType == Res_value::TYPE_NULL) continue;
3074                ALOGI("      0x%08x: t=0x%x, d=0x%08x (block=%d)\n",
3075                     (int)Res_MAKEID(i, j, k),
3076                     te.value.dataType, (int)te.value.data, (int)te.stringBlock);
3077            }
3078        }
3079    }
3080}
3081
3082ResTable::ResTable()
3083    : mError(NO_INIT)
3084{
3085    memset(&mParams, 0, sizeof(mParams));
3086    memset(mPackageMap, 0, sizeof(mPackageMap));
3087    //ALOGI("Creating ResTable %p\n", this);
3088}
3089
3090ResTable::ResTable(const void* data, size_t size, const int32_t cookie, bool copyData)
3091    : mError(NO_INIT)
3092{
3093    memset(&mParams, 0, sizeof(mParams));
3094    memset(mPackageMap, 0, sizeof(mPackageMap));
3095    addInternal(data, size, cookie, NULL /* asset */, copyData, NULL /* idMap */);
3096    LOG_FATAL_IF(mError != NO_ERROR, "Error parsing resource table");
3097    //ALOGI("Creating ResTable %p\n", this);
3098}
3099
3100ResTable::~ResTable()
3101{
3102    //ALOGI("Destroying ResTable in %p\n", this);
3103    uninit();
3104}
3105
3106inline ssize_t ResTable::getResourcePackageIndex(uint32_t resID) const
3107{
3108    return ((ssize_t)mPackageMap[Res_GETPACKAGE(resID)+1])-1;
3109}
3110
3111status_t ResTable::add(const void* data, size_t size) {
3112    return addInternal(data, size, 0 /* cookie */, NULL /* asset */,
3113            false /* copyData */, NULL /* idMap */);
3114}
3115
3116status_t ResTable::add(Asset* asset, const int32_t cookie, bool copyData, const void* idmap)
3117{
3118    const void* data = asset->getBuffer(true);
3119    if (data == NULL) {
3120        ALOGW("Unable to get buffer of resource asset file");
3121        return UNKNOWN_ERROR;
3122    }
3123    size_t size = (size_t)asset->getLength();
3124    return addInternal(data, size, cookie, asset, copyData,
3125            reinterpret_cast<const Asset*>(idmap));
3126}
3127
3128status_t ResTable::add(ResTable* src)
3129{
3130    mError = src->mError;
3131
3132    for (size_t i=0; i<src->mHeaders.size(); i++) {
3133        mHeaders.add(src->mHeaders[i]);
3134    }
3135
3136    for (size_t i=0; i<src->mPackageGroups.size(); i++) {
3137        PackageGroup* srcPg = src->mPackageGroups[i];
3138        PackageGroup* pg = new PackageGroup(this, srcPg->name, srcPg->id);
3139        for (size_t j=0; j<srcPg->packages.size(); j++) {
3140            pg->packages.add(srcPg->packages[j]);
3141        }
3142        pg->basePackage = srcPg->basePackage;
3143        pg->typeCount = srcPg->typeCount;
3144        mPackageGroups.add(pg);
3145    }
3146
3147    memcpy(mPackageMap, src->mPackageMap, sizeof(mPackageMap));
3148
3149    return mError;
3150}
3151
3152status_t ResTable::addInternal(const void* data, size_t size, const int32_t cookie,
3153                       Asset* /*asset*/, bool copyData, const Asset* idmap)
3154{
3155    if (!data) return NO_ERROR;
3156    Header* header = new Header(this);
3157    header->index = mHeaders.size();
3158    header->cookie = cookie;
3159    if (idmap != NULL) {
3160        const size_t idmap_size = idmap->getLength();
3161        const void* idmap_data = const_cast<Asset*>(idmap)->getBuffer(true);
3162        header->resourceIDMap = (uint32_t*)malloc(idmap_size);
3163        if (header->resourceIDMap == NULL) {
3164            delete header;
3165            return (mError = NO_MEMORY);
3166        }
3167        memcpy((void*)header->resourceIDMap, idmap_data, idmap_size);
3168        header->resourceIDMapSize = idmap_size;
3169    }
3170    mHeaders.add(header);
3171
3172    const bool notDeviceEndian = htods(0xf0) != 0xf0;
3173
3174    LOAD_TABLE_NOISY(
3175        ALOGV("Adding resources to ResTable: data=%p, size=0x%x, cookie=%d, asset=%p, copy=%d "
3176             "idmap=%p\n", data, size, cookie, asset, copyData, idmap));
3177
3178    if (copyData || notDeviceEndian) {
3179        header->ownedData = malloc(size);
3180        if (header->ownedData == NULL) {
3181            return (mError=NO_MEMORY);
3182        }
3183        memcpy(header->ownedData, data, size);
3184        data = header->ownedData;
3185    }
3186
3187    header->header = (const ResTable_header*)data;
3188    header->size = dtohl(header->header->header.size);
3189    //ALOGI("Got size 0x%x, again size 0x%x, raw size 0x%x\n", header->size,
3190    //     dtohl(header->header->header.size), header->header->header.size);
3191    LOAD_TABLE_NOISY(ALOGV("Loading ResTable @%p:\n", header->header));
3192    LOAD_TABLE_NOISY(printHexData(2, header->header, header->size < 256 ? header->size : 256,
3193                                  16, 16, 0, false, printToLogFunc));
3194    if (dtohs(header->header->header.headerSize) > header->size
3195            || header->size > size) {
3196        ALOGW("Bad resource table: header size 0x%x or total size 0x%x is larger than data size 0x%x\n",
3197             (int)dtohs(header->header->header.headerSize),
3198             (int)header->size, (int)size);
3199        return (mError=BAD_TYPE);
3200    }
3201    if (((dtohs(header->header->header.headerSize)|header->size)&0x3) != 0) {
3202        ALOGW("Bad resource table: header size 0x%x or total size 0x%x is not on an integer boundary\n",
3203             (int)dtohs(header->header->header.headerSize),
3204             (int)header->size);
3205        return (mError=BAD_TYPE);
3206    }
3207    header->dataEnd = ((const uint8_t*)header->header) + header->size;
3208
3209    // Iterate through all chunks.
3210    size_t curPackage = 0;
3211
3212    const ResChunk_header* chunk =
3213        (const ResChunk_header*)(((const uint8_t*)header->header)
3214                                 + dtohs(header->header->header.headerSize));
3215    while (((const uint8_t*)chunk) <= (header->dataEnd-sizeof(ResChunk_header)) &&
3216           ((const uint8_t*)chunk) <= (header->dataEnd-dtohl(chunk->size))) {
3217        status_t err = validate_chunk(chunk, sizeof(ResChunk_header), header->dataEnd, "ResTable");
3218        if (err != NO_ERROR) {
3219            return (mError=err);
3220        }
3221        TABLE_NOISY(ALOGV("Chunk: type=0x%x, headerSize=0x%x, size=0x%x, pos=%p\n",
3222                     dtohs(chunk->type), dtohs(chunk->headerSize), dtohl(chunk->size),
3223                     (void*)(((const uint8_t*)chunk) - ((const uint8_t*)header->header))));
3224        const size_t csize = dtohl(chunk->size);
3225        const uint16_t ctype = dtohs(chunk->type);
3226        if (ctype == RES_STRING_POOL_TYPE) {
3227            if (header->values.getError() != NO_ERROR) {
3228                // Only use the first string chunk; ignore any others that
3229                // may appear.
3230                status_t err = header->values.setTo(chunk, csize);
3231                if (err != NO_ERROR) {
3232                    return (mError=err);
3233                }
3234            } else {
3235                ALOGW("Multiple string chunks found in resource table.");
3236            }
3237        } else if (ctype == RES_TABLE_PACKAGE_TYPE) {
3238            if (curPackage >= dtohl(header->header->packageCount)) {
3239                ALOGW("More package chunks were found than the %d declared in the header.",
3240                     dtohl(header->header->packageCount));
3241                return (mError=BAD_TYPE);
3242            }
3243            uint32_t idmap_id = 0;
3244            if (idmap != NULL) {
3245                uint32_t tmp;
3246                if (getIdmapPackageId(header->resourceIDMap,
3247                                      header->resourceIDMapSize,
3248                                      &tmp) == NO_ERROR) {
3249                    idmap_id = tmp;
3250                }
3251            }
3252            if (parsePackage((ResTable_package*)chunk, header, idmap_id) != NO_ERROR) {
3253                return mError;
3254            }
3255            curPackage++;
3256        } else {
3257            ALOGW("Unknown chunk type 0x%x in table at %p.\n",
3258                 ctype,
3259                 (void*)(((const uint8_t*)chunk) - ((const uint8_t*)header->header)));
3260        }
3261        chunk = (const ResChunk_header*)
3262            (((const uint8_t*)chunk) + csize);
3263    }
3264
3265    if (curPackage < dtohl(header->header->packageCount)) {
3266        ALOGW("Fewer package chunks (%d) were found than the %d declared in the header.",
3267             (int)curPackage, dtohl(header->header->packageCount));
3268        return (mError=BAD_TYPE);
3269    }
3270    mError = header->values.getError();
3271    if (mError != NO_ERROR) {
3272        ALOGW("No string values found in resource table!");
3273    }
3274
3275    TABLE_NOISY(ALOGV("Returning from add with mError=%d\n", mError));
3276    return mError;
3277}
3278
3279status_t ResTable::getError() const
3280{
3281    return mError;
3282}
3283
3284void ResTable::uninit()
3285{
3286    mError = NO_INIT;
3287    size_t N = mPackageGroups.size();
3288    for (size_t i=0; i<N; i++) {
3289        PackageGroup* g = mPackageGroups[i];
3290        delete g;
3291    }
3292    N = mHeaders.size();
3293    for (size_t i=0; i<N; i++) {
3294        Header* header = mHeaders[i];
3295        if (header->owner == this) {
3296            if (header->ownedData) {
3297                free(header->ownedData);
3298            }
3299            delete header;
3300        }
3301    }
3302
3303    mPackageGroups.clear();
3304    mHeaders.clear();
3305}
3306
3307bool ResTable::getResourceName(uint32_t resID, bool allowUtf8, resource_name* outName) const
3308{
3309    if (mError != NO_ERROR) {
3310        return false;
3311    }
3312
3313    const ssize_t p = getResourcePackageIndex(resID);
3314    const int t = Res_GETTYPE(resID);
3315    const int e = Res_GETENTRY(resID);
3316
3317    if (p < 0) {
3318        if (Res_GETPACKAGE(resID)+1 == 0) {
3319            ALOGW("No package identifier when getting name for resource number 0x%08x", resID);
3320        } else {
3321            ALOGW("No known package when getting name for resource number 0x%08x", resID);
3322        }
3323        return false;
3324    }
3325    if (t < 0) {
3326        ALOGW("No type identifier when getting name for resource number 0x%08x", resID);
3327        return false;
3328    }
3329
3330    const PackageGroup* const grp = mPackageGroups[p];
3331    if (grp == NULL) {
3332        ALOGW("Bad identifier when getting name for resource number 0x%08x", resID);
3333        return false;
3334    }
3335    if (grp->packages.size() > 0) {
3336        const Package* const package = grp->packages[0];
3337
3338        const ResTable_type* type;
3339        const ResTable_entry* entry;
3340        ssize_t offset = getEntry(package, t, e, NULL, &type, &entry, NULL);
3341        if (offset <= 0) {
3342            return false;
3343        }
3344
3345        outName->package = grp->name.string();
3346        outName->packageLen = grp->name.size();
3347        if (allowUtf8) {
3348            outName->type8 = grp->basePackage->typeStrings.string8At(t, &outName->typeLen);
3349            outName->name8 = grp->basePackage->keyStrings.string8At(
3350                dtohl(entry->key.index), &outName->nameLen);
3351        } else {
3352            outName->type8 = NULL;
3353            outName->name8 = NULL;
3354        }
3355        if (outName->type8 == NULL) {
3356            outName->type = grp->basePackage->typeStrings.stringAt(t, &outName->typeLen);
3357            // If we have a bad index for some reason, we should abort.
3358            if (outName->type == NULL) {
3359                return false;
3360            }
3361        }
3362        if (outName->name8 == NULL) {
3363            outName->name = grp->basePackage->keyStrings.stringAt(
3364                dtohl(entry->key.index), &outName->nameLen);
3365            // If we have a bad index for some reason, we should abort.
3366            if (outName->name == NULL) {
3367                return false;
3368            }
3369        }
3370
3371        return true;
3372    }
3373
3374    return false;
3375}
3376
3377ssize_t ResTable::getResource(uint32_t resID, Res_value* outValue, bool mayBeBag, uint16_t density,
3378        uint32_t* outSpecFlags, ResTable_config* outConfig) const
3379{
3380    if (mError != NO_ERROR) {
3381        return mError;
3382    }
3383
3384    const ssize_t p = getResourcePackageIndex(resID);
3385    const int t = Res_GETTYPE(resID);
3386    const int e = Res_GETENTRY(resID);
3387
3388    if (p < 0) {
3389        if (Res_GETPACKAGE(resID)+1 == 0) {
3390            ALOGW("No package identifier when getting value for resource number 0x%08x", resID);
3391        } else {
3392            ALOGW("No known package when getting value for resource number 0x%08x", resID);
3393        }
3394        return BAD_INDEX;
3395    }
3396    if (t < 0) {
3397        ALOGW("No type identifier when getting value for resource number 0x%08x", resID);
3398        return BAD_INDEX;
3399    }
3400
3401    const Res_value* bestValue = NULL;
3402    const Package* bestPackage = NULL;
3403    ResTable_config bestItem;
3404    memset(&bestItem, 0, sizeof(bestItem)); // make the compiler shut up
3405
3406    if (outSpecFlags != NULL) *outSpecFlags = 0;
3407
3408    // Look through all resource packages, starting with the most
3409    // recently added.
3410    const PackageGroup* const grp = mPackageGroups[p];
3411    if (grp == NULL) {
3412        ALOGW("Bad identifier when getting value for resource number 0x%08x", resID);
3413        return BAD_INDEX;
3414    }
3415
3416    // Allow overriding density
3417    const ResTable_config* desiredConfig = &mParams;
3418    ResTable_config* overrideConfig = NULL;
3419    if (density > 0) {
3420        overrideConfig = (ResTable_config*) malloc(sizeof(ResTable_config));
3421        if (overrideConfig == NULL) {
3422            ALOGE("Couldn't malloc ResTable_config for overrides: %s", strerror(errno));
3423            return BAD_INDEX;
3424        }
3425        memcpy(overrideConfig, &mParams, sizeof(ResTable_config));
3426        overrideConfig->density = density;
3427        desiredConfig = overrideConfig;
3428    }
3429
3430    ssize_t rc = BAD_VALUE;
3431    size_t ip = grp->packages.size();
3432    while (ip > 0) {
3433        ip--;
3434        int T = t;
3435        int E = e;
3436
3437        const Package* const package = grp->packages[ip];
3438        if (package->header->resourceIDMap) {
3439            uint32_t overlayResID = 0x0;
3440            status_t retval = idmapLookup(package->header->resourceIDMap,
3441                                          package->header->resourceIDMapSize,
3442                                          resID, &overlayResID);
3443            if (retval == NO_ERROR && overlayResID != 0x0) {
3444                // for this loop iteration, this is the type and entry we really want
3445                ALOGV("resource map 0x%08x -> 0x%08x\n", resID, overlayResID);
3446                T = Res_GETTYPE(overlayResID);
3447                E = Res_GETENTRY(overlayResID);
3448            } else {
3449                // resource not present in overlay package, continue with the next package
3450                continue;
3451            }
3452        }
3453
3454        const ResTable_type* type;
3455        const ResTable_entry* entry;
3456        const Type* typeClass;
3457        ssize_t offset = getEntry(package, T, E, desiredConfig, &type, &entry, &typeClass);
3458        if (offset <= 0) {
3459            // No {entry, appropriate config} pair found in package. If this
3460            // package is an overlay package (ip != 0), this simply means the
3461            // overlay package did not specify a default.
3462            // Non-overlay packages are still required to provide a default.
3463            if (offset < 0 && ip == 0) {
3464                ALOGW("Failure getting entry for 0x%08x (t=%d e=%d) in package %zd (error %d)\n",
3465                        resID, T, E, ip, (int)offset);
3466                rc = offset;
3467                goto out;
3468            }
3469            continue;
3470        }
3471
3472        if ((dtohs(entry->flags)&entry->FLAG_COMPLEX) != 0) {
3473            if (!mayBeBag) {
3474                ALOGW("Requesting resource 0x%x failed because it is complex\n",
3475                     resID);
3476            }
3477            continue;
3478        }
3479
3480        TABLE_NOISY(aout << "Resource type data: "
3481              << HexDump(type, dtohl(type->header.size)) << endl);
3482
3483        if ((size_t)offset > (dtohl(type->header.size)-sizeof(Res_value))) {
3484            ALOGW("ResTable_item at %d is beyond type chunk data %d",
3485                 (int)offset, dtohl(type->header.size));
3486            rc = BAD_TYPE;
3487            goto out;
3488        }
3489
3490        const Res_value* item =
3491            (const Res_value*)(((const uint8_t*)type) + offset);
3492        ResTable_config thisConfig;
3493        thisConfig.copyFromDtoH(type->config);
3494
3495        if (outSpecFlags != NULL) {
3496            if (typeClass->typeSpecFlags != NULL) {
3497                *outSpecFlags |= dtohl(typeClass->typeSpecFlags[E]);
3498            } else {
3499                *outSpecFlags = -1;
3500            }
3501        }
3502
3503        if (bestPackage != NULL &&
3504            (bestItem.isMoreSpecificThan(thisConfig) || bestItem.diff(thisConfig) == 0)) {
3505            // Discard thisConfig not only if bestItem is more specific, but also if the two configs
3506            // are identical (diff == 0), or overlay packages will not take effect.
3507            continue;
3508        }
3509
3510        bestItem = thisConfig;
3511        bestValue = item;
3512        bestPackage = package;
3513    }
3514
3515    TABLE_NOISY(printf("Found result: package %p\n", bestPackage));
3516
3517    if (bestValue) {
3518        outValue->size = dtohs(bestValue->size);
3519        outValue->res0 = bestValue->res0;
3520        outValue->dataType = bestValue->dataType;
3521        outValue->data = dtohl(bestValue->data);
3522        if (outConfig != NULL) {
3523            *outConfig = bestItem;
3524        }
3525        TABLE_NOISY(size_t len;
3526              printf("Found value: pkg=%d, type=%d, str=%s, int=%d\n",
3527                     bestPackage->header->index,
3528                     outValue->dataType,
3529                     outValue->dataType == bestValue->TYPE_STRING
3530                     ? String8(bestPackage->header->values.stringAt(
3531                         outValue->data, &len)).string()
3532                     : "",
3533                     outValue->data));
3534        rc = bestPackage->header->index;
3535        goto out;
3536    }
3537
3538out:
3539    if (overrideConfig != NULL) {
3540        free(overrideConfig);
3541    }
3542
3543    return rc;
3544}
3545
3546ssize_t ResTable::resolveReference(Res_value* value, ssize_t blockIndex,
3547        uint32_t* outLastRef, uint32_t* inoutTypeSpecFlags,
3548        ResTable_config* outConfig) const
3549{
3550    int count=0;
3551    while (blockIndex >= 0 && value->dataType == value->TYPE_REFERENCE
3552           && value->data != 0 && count < 20) {
3553        if (outLastRef) *outLastRef = value->data;
3554        uint32_t lastRef = value->data;
3555        uint32_t newFlags = 0;
3556        const ssize_t newIndex = getResource(value->data, value, true, 0, &newFlags,
3557                outConfig);
3558        if (newIndex == BAD_INDEX) {
3559            return BAD_INDEX;
3560        }
3561        TABLE_THEME(ALOGI("Resolving reference %p: newIndex=%d, type=0x%x, data=%p\n",
3562             (void*)lastRef, (int)newIndex, (int)value->dataType, (void*)value->data));
3563        //printf("Getting reference 0x%08x: newIndex=%d\n", value->data, newIndex);
3564        if (inoutTypeSpecFlags != NULL) *inoutTypeSpecFlags |= newFlags;
3565        if (newIndex < 0) {
3566            // This can fail if the resource being referenced is a style...
3567            // in this case, just return the reference, and expect the
3568            // caller to deal with.
3569            return blockIndex;
3570        }
3571        blockIndex = newIndex;
3572        count++;
3573    }
3574    return blockIndex;
3575}
3576
3577const char16_t* ResTable::valueToString(
3578    const Res_value* value, size_t stringBlock,
3579    char16_t /*tmpBuffer*/ [TMP_BUFFER_SIZE], size_t* outLen)
3580{
3581    if (!value) {
3582        return NULL;
3583    }
3584    if (value->dataType == value->TYPE_STRING) {
3585        return getTableStringBlock(stringBlock)->stringAt(value->data, outLen);
3586    }
3587    // XXX do int to string conversions.
3588    return NULL;
3589}
3590
3591ssize_t ResTable::lockBag(uint32_t resID, const bag_entry** outBag) const
3592{
3593    mLock.lock();
3594    ssize_t err = getBagLocked(resID, outBag);
3595    if (err < NO_ERROR) {
3596        //printf("*** get failed!  unlocking\n");
3597        mLock.unlock();
3598    }
3599    return err;
3600}
3601
3602void ResTable::unlockBag(const bag_entry* /*bag*/) const
3603{
3604    //printf("<<< unlockBag %p\n", this);
3605    mLock.unlock();
3606}
3607
3608void ResTable::lock() const
3609{
3610    mLock.lock();
3611}
3612
3613void ResTable::unlock() const
3614{
3615    mLock.unlock();
3616}
3617
3618ssize_t ResTable::getBagLocked(uint32_t resID, const bag_entry** outBag,
3619        uint32_t* outTypeSpecFlags) const
3620{
3621    if (mError != NO_ERROR) {
3622        return mError;
3623    }
3624
3625    const ssize_t p = getResourcePackageIndex(resID);
3626    const int t = Res_GETTYPE(resID);
3627    const int e = Res_GETENTRY(resID);
3628
3629    if (p < 0) {
3630        ALOGW("Invalid package identifier when getting bag for resource number 0x%08x", resID);
3631        return BAD_INDEX;
3632    }
3633    if (t < 0) {
3634        ALOGW("No type identifier when getting bag for resource number 0x%08x", resID);
3635        return BAD_INDEX;
3636    }
3637
3638    //printf("Get bag: id=0x%08x, p=%d, t=%d\n", resID, p, t);
3639    PackageGroup* const grp = mPackageGroups[p];
3640    if (grp == NULL) {
3641        ALOGW("Bad identifier when getting bag for resource number 0x%08x", resID);
3642        return false;
3643    }
3644
3645    if (t >= (int)grp->typeCount) {
3646        ALOGW("Type identifier 0x%x is larger than type count 0x%x",
3647             t+1, (int)grp->typeCount);
3648        return BAD_INDEX;
3649    }
3650
3651    const Package* const basePackage = grp->packages[0];
3652
3653    const Type* const typeConfigs = basePackage->getType(t);
3654
3655    const size_t NENTRY = typeConfigs->entryCount;
3656    if (e >= (int)NENTRY) {
3657        ALOGW("Entry identifier 0x%x is larger than entry count 0x%x",
3658             e, (int)typeConfigs->entryCount);
3659        return BAD_INDEX;
3660    }
3661
3662    // First see if we've already computed this bag...
3663    if (grp->bags) {
3664        bag_set** typeSet = grp->bags[t];
3665        if (typeSet) {
3666            bag_set* set = typeSet[e];
3667            if (set) {
3668                if (set != (bag_set*)0xFFFFFFFF) {
3669                    if (outTypeSpecFlags != NULL) {
3670                        *outTypeSpecFlags = set->typeSpecFlags;
3671                    }
3672                    *outBag = (bag_entry*)(set+1);
3673                    //ALOGI("Found existing bag for: %p\n", (void*)resID);
3674                    return set->numAttrs;
3675                }
3676                ALOGW("Attempt to retrieve bag 0x%08x which is invalid or in a cycle.",
3677                     resID);
3678                return BAD_INDEX;
3679            }
3680        }
3681    }
3682
3683    // Bag not found, we need to compute it!
3684    if (!grp->bags) {
3685        grp->bags = (bag_set***)calloc(grp->typeCount, sizeof(bag_set*));
3686        if (!grp->bags) return NO_MEMORY;
3687    }
3688
3689    bag_set** typeSet = grp->bags[t];
3690    if (!typeSet) {
3691        typeSet = (bag_set**)calloc(NENTRY, sizeof(bag_set*));
3692        if (!typeSet) return NO_MEMORY;
3693        grp->bags[t] = typeSet;
3694    }
3695
3696    // Mark that we are currently working on this one.
3697    typeSet[e] = (bag_set*)0xFFFFFFFF;
3698
3699    // This is what we are building.
3700    bag_set* set = NULL;
3701
3702    TABLE_NOISY(ALOGI("Building bag: %p\n", (void*)resID));
3703
3704    ResTable_config bestConfig;
3705    memset(&bestConfig, 0, sizeof(bestConfig));
3706
3707    // Now collect all bag attributes from all packages.
3708    size_t ip = grp->packages.size();
3709    while (ip > 0) {
3710        ip--;
3711        int T = t;
3712        int E = e;
3713
3714        const Package* const package = grp->packages[ip];
3715        if (package->header->resourceIDMap) {
3716            uint32_t overlayResID = 0x0;
3717            status_t retval = idmapLookup(package->header->resourceIDMap,
3718                                          package->header->resourceIDMapSize,
3719                                          resID, &overlayResID);
3720            if (retval == NO_ERROR && overlayResID != 0x0) {
3721                // for this loop iteration, this is the type and entry we really want
3722                ALOGV("resource map 0x%08x -> 0x%08x\n", resID, overlayResID);
3723                T = Res_GETTYPE(overlayResID);
3724                E = Res_GETENTRY(overlayResID);
3725            } else {
3726                // resource not present in overlay package, continue with the next package
3727                continue;
3728            }
3729        }
3730
3731        const ResTable_type* type;
3732        const ResTable_entry* entry;
3733        const Type* typeClass;
3734        ALOGV("Getting entry pkg=%p, t=%d, e=%d\n", package, T, E);
3735        ssize_t offset = getEntry(package, T, E, &mParams, &type, &entry, &typeClass);
3736        ALOGV("Resulting offset=%d\n", offset);
3737        if (offset <= 0) {
3738            // No {entry, appropriate config} pair found in package. If this
3739            // package is an overlay package (ip != 0), this simply means the
3740            // overlay package did not specify a default.
3741            // Non-overlay packages are still required to provide a default.
3742            if (offset < 0 && ip == 0) {
3743                if (set) free(set);
3744                return offset;
3745            }
3746            continue;
3747        }
3748
3749        if ((dtohs(entry->flags)&entry->FLAG_COMPLEX) == 0) {
3750            ALOGW("Skipping entry 0x%x in package table %zu because it is not complex!\n",
3751                 resID, ip);
3752            continue;
3753        }
3754
3755        if (set != NULL && !type->config.isBetterThan(bestConfig, NULL)) {
3756            continue;
3757        }
3758        bestConfig = type->config;
3759        if (set) {
3760            free(set);
3761            set = NULL;
3762        }
3763
3764        const uint16_t entrySize = dtohs(entry->size);
3765        const uint32_t parent = entrySize >= sizeof(ResTable_map_entry)
3766            ? dtohl(((const ResTable_map_entry*)entry)->parent.ident) : 0;
3767        const uint32_t count = entrySize >= sizeof(ResTable_map_entry)
3768            ? dtohl(((const ResTable_map_entry*)entry)->count) : 0;
3769
3770        size_t N = count;
3771
3772        TABLE_NOISY(ALOGI("Found map: size=%p parent=%p count=%d\n",
3773                         entrySize, parent, count));
3774
3775        // If this map inherits from another, we need to start
3776        // with its parent's values.  Otherwise start out empty.
3777        TABLE_NOISY(printf("Creating new bag, entrySize=0x%08x, parent=0x%08x\n",
3778                           entrySize, parent));
3779        if (parent) {
3780            const bag_entry* parentBag;
3781            uint32_t parentTypeSpecFlags = 0;
3782            const ssize_t NP = getBagLocked(parent, &parentBag, &parentTypeSpecFlags);
3783            const size_t NT = ((NP >= 0) ? NP : 0) + N;
3784            set = (bag_set*)malloc(sizeof(bag_set)+sizeof(bag_entry)*NT);
3785            if (set == NULL) {
3786                return NO_MEMORY;
3787            }
3788            if (NP > 0) {
3789                memcpy(set+1, parentBag, NP*sizeof(bag_entry));
3790                set->numAttrs = NP;
3791                TABLE_NOISY(ALOGI("Initialized new bag with %d inherited attributes.\n", NP));
3792            } else {
3793                TABLE_NOISY(ALOGI("Initialized new bag with no inherited attributes.\n"));
3794                set->numAttrs = 0;
3795            }
3796            set->availAttrs = NT;
3797            set->typeSpecFlags = parentTypeSpecFlags;
3798        } else {
3799            set = (bag_set*)malloc(sizeof(bag_set)+sizeof(bag_entry)*N);
3800            if (set == NULL) {
3801                return NO_MEMORY;
3802            }
3803            set->numAttrs = 0;
3804            set->availAttrs = N;
3805            set->typeSpecFlags = 0;
3806        }
3807
3808        if (typeClass->typeSpecFlags != NULL) {
3809            set->typeSpecFlags |= dtohl(typeClass->typeSpecFlags[E]);
3810        } else {
3811            set->typeSpecFlags = -1;
3812        }
3813
3814        // Now merge in the new attributes...
3815        ssize_t curOff = offset;
3816        const ResTable_map* map;
3817        bag_entry* entries = (bag_entry*)(set+1);
3818        size_t curEntry = 0;
3819        uint32_t pos = 0;
3820        TABLE_NOISY(ALOGI("Starting with set %p, entries=%p, avail=%d\n",
3821                     set, entries, set->availAttrs));
3822        while (pos < count) {
3823            TABLE_NOISY(printf("Now at %p\n", (void*)curOff));
3824
3825            if ((size_t)curOff > (dtohl(type->header.size)-sizeof(ResTable_map))) {
3826                ALOGW("ResTable_map at %d is beyond type chunk data %d",
3827                     (int)curOff, dtohl(type->header.size));
3828                return BAD_TYPE;
3829            }
3830            map = (const ResTable_map*)(((const uint8_t*)type) + curOff);
3831            N++;
3832
3833            const uint32_t newName = htodl(map->name.ident);
3834            bool isInside;
3835            uint32_t oldName = 0;
3836            while ((isInside=(curEntry < set->numAttrs))
3837                    && (oldName=entries[curEntry].map.name.ident) < newName) {
3838                TABLE_NOISY(printf("#%d: Keeping existing attribute: 0x%08x\n",
3839                             curEntry, entries[curEntry].map.name.ident));
3840                curEntry++;
3841            }
3842
3843            if ((!isInside) || oldName != newName) {
3844                // This is a new attribute...  figure out what to do with it.
3845                if (set->numAttrs >= set->availAttrs) {
3846                    // Need to alloc more memory...
3847                    const size_t newAvail = set->availAttrs+N;
3848                    set = (bag_set*)realloc(set,
3849                                            sizeof(bag_set)
3850                                            + sizeof(bag_entry)*newAvail);
3851                    if (set == NULL) {
3852                        return NO_MEMORY;
3853                    }
3854                    set->availAttrs = newAvail;
3855                    entries = (bag_entry*)(set+1);
3856                    TABLE_NOISY(printf("Reallocated set %p, entries=%p, avail=%d\n",
3857                                 set, entries, set->availAttrs));
3858                }
3859                if (isInside) {
3860                    // Going in the middle, need to make space.
3861                    memmove(entries+curEntry+1, entries+curEntry,
3862                            sizeof(bag_entry)*(set->numAttrs-curEntry));
3863                    set->numAttrs++;
3864                }
3865                TABLE_NOISY(printf("#%d: Inserting new attribute: 0x%08x\n",
3866                             curEntry, newName));
3867            } else {
3868                TABLE_NOISY(printf("#%d: Replacing existing attribute: 0x%08x\n",
3869                             curEntry, oldName));
3870            }
3871
3872            bag_entry* cur = entries+curEntry;
3873
3874            cur->stringBlock = package->header->index;
3875            cur->map.name.ident = newName;
3876            cur->map.value.copyFrom_dtoh(map->value);
3877            TABLE_NOISY(printf("Setting entry #%d %p: block=%d, name=0x%08x, type=%d, data=0x%08x\n",
3878                         curEntry, cur, cur->stringBlock, cur->map.name.ident,
3879                         cur->map.value.dataType, cur->map.value.data));
3880
3881            // On to the next!
3882            curEntry++;
3883            pos++;
3884            const size_t size = dtohs(map->value.size);
3885            curOff += size + sizeof(*map)-sizeof(map->value);
3886        };
3887        if (curEntry > set->numAttrs) {
3888            set->numAttrs = curEntry;
3889        }
3890    }
3891
3892    // And this is it...
3893    typeSet[e] = set;
3894    if (set) {
3895        if (outTypeSpecFlags != NULL) {
3896            *outTypeSpecFlags = set->typeSpecFlags;
3897        }
3898        *outBag = (bag_entry*)(set+1);
3899        TABLE_NOISY(ALOGI("Returning %d attrs\n", set->numAttrs));
3900        return set->numAttrs;
3901    }
3902    return BAD_INDEX;
3903}
3904
3905void ResTable::setParameters(const ResTable_config* params)
3906{
3907    mLock.lock();
3908    TABLE_GETENTRY(ALOGI("Setting parameters: %s\n", params->toString().string()));
3909    mParams = *params;
3910    for (size_t i=0; i<mPackageGroups.size(); i++) {
3911        TABLE_NOISY(ALOGI("CLEARING BAGS FOR GROUP %d!", i));
3912        mPackageGroups[i]->clearBagCache();
3913    }
3914    mLock.unlock();
3915}
3916
3917void ResTable::getParameters(ResTable_config* params) const
3918{
3919    mLock.lock();
3920    *params = mParams;
3921    mLock.unlock();
3922}
3923
3924struct id_name_map {
3925    uint32_t id;
3926    size_t len;
3927    char16_t name[6];
3928};
3929
3930const static id_name_map ID_NAMES[] = {
3931    { ResTable_map::ATTR_TYPE,  5, { '^', 't', 'y', 'p', 'e' } },
3932    { ResTable_map::ATTR_L10N,  5, { '^', 'l', '1', '0', 'n' } },
3933    { ResTable_map::ATTR_MIN,   4, { '^', 'm', 'i', 'n' } },
3934    { ResTable_map::ATTR_MAX,   4, { '^', 'm', 'a', 'x' } },
3935    { ResTable_map::ATTR_OTHER, 6, { '^', 'o', 't', 'h', 'e', 'r' } },
3936    { ResTable_map::ATTR_ZERO,  5, { '^', 'z', 'e', 'r', 'o' } },
3937    { ResTable_map::ATTR_ONE,   4, { '^', 'o', 'n', 'e' } },
3938    { ResTable_map::ATTR_TWO,   4, { '^', 't', 'w', 'o' } },
3939    { ResTable_map::ATTR_FEW,   4, { '^', 'f', 'e', 'w' } },
3940    { ResTable_map::ATTR_MANY,  5, { '^', 'm', 'a', 'n', 'y' } },
3941};
3942
3943uint32_t ResTable::identifierForName(const char16_t* name, size_t nameLen,
3944                                     const char16_t* type, size_t typeLen,
3945                                     const char16_t* package,
3946                                     size_t packageLen,
3947                                     uint32_t* outTypeSpecFlags) const
3948{
3949    TABLE_SUPER_NOISY(printf("Identifier for name: error=%d\n", mError));
3950
3951    // Check for internal resource identifier as the very first thing, so
3952    // that we will always find them even when there are no resources.
3953    if (name[0] == '^') {
3954        const int N = (sizeof(ID_NAMES)/sizeof(ID_NAMES[0]));
3955        size_t len;
3956        for (int i=0; i<N; i++) {
3957            const id_name_map* m = ID_NAMES + i;
3958            len = m->len;
3959            if (len != nameLen) {
3960                continue;
3961            }
3962            for (size_t j=1; j<len; j++) {
3963                if (m->name[j] != name[j]) {
3964                    goto nope;
3965                }
3966            }
3967            if (outTypeSpecFlags) {
3968                *outTypeSpecFlags = ResTable_typeSpec::SPEC_PUBLIC;
3969            }
3970            return m->id;
3971nope:
3972            ;
3973        }
3974        if (nameLen > 7) {
3975            if (name[1] == 'i' && name[2] == 'n'
3976                && name[3] == 'd' && name[4] == 'e' && name[5] == 'x'
3977                && name[6] == '_') {
3978                int index = atoi(String8(name + 7, nameLen - 7).string());
3979                if (Res_CHECKID(index)) {
3980                    ALOGW("Array resource index: %d is too large.",
3981                         index);
3982                    return 0;
3983                }
3984                if (outTypeSpecFlags) {
3985                    *outTypeSpecFlags = ResTable_typeSpec::SPEC_PUBLIC;
3986                }
3987                return  Res_MAKEARRAY(index);
3988            }
3989        }
3990        return 0;
3991    }
3992
3993    if (mError != NO_ERROR) {
3994        return 0;
3995    }
3996
3997    bool fakePublic = false;
3998
3999    // Figure out the package and type we are looking in...
4000
4001    const char16_t* packageEnd = NULL;
4002    const char16_t* typeEnd = NULL;
4003    const char16_t* const nameEnd = name+nameLen;
4004    const char16_t* p = name;
4005    while (p < nameEnd) {
4006        if (*p == ':') packageEnd = p;
4007        else if (*p == '/') typeEnd = p;
4008        p++;
4009    }
4010    if (*name == '@') {
4011        name++;
4012        if (*name == '*') {
4013            fakePublic = true;
4014            name++;
4015        }
4016    }
4017    if (name >= nameEnd) {
4018        return 0;
4019    }
4020
4021    if (packageEnd) {
4022        package = name;
4023        packageLen = packageEnd-name;
4024        name = packageEnd+1;
4025    } else if (!package) {
4026        return 0;
4027    }
4028
4029    if (typeEnd) {
4030        type = name;
4031        typeLen = typeEnd-name;
4032        name = typeEnd+1;
4033    } else if (!type) {
4034        return 0;
4035    }
4036
4037    if (name >= nameEnd) {
4038        return 0;
4039    }
4040    nameLen = nameEnd-name;
4041
4042    TABLE_NOISY(printf("Looking for identifier: type=%s, name=%s, package=%s\n",
4043                 String8(type, typeLen).string(),
4044                 String8(name, nameLen).string(),
4045                 String8(package, packageLen).string()));
4046
4047    const size_t NG = mPackageGroups.size();
4048    for (size_t ig=0; ig<NG; ig++) {
4049        const PackageGroup* group = mPackageGroups[ig];
4050
4051        if (strzcmp16(package, packageLen,
4052                      group->name.string(), group->name.size())) {
4053            TABLE_NOISY(printf("Skipping package group: %s\n", String8(group->name).string()));
4054            continue;
4055        }
4056
4057        const ssize_t ti = group->basePackage->typeStrings.indexOfString(type, typeLen);
4058        if (ti < 0) {
4059            TABLE_NOISY(printf("Type not found in package %s\n", String8(group->name).string()));
4060            continue;
4061        }
4062
4063        const ssize_t ei = group->basePackage->keyStrings.indexOfString(name, nameLen);
4064        if (ei < 0) {
4065            TABLE_NOISY(printf("Name not found in package %s\n", String8(group->name).string()));
4066            continue;
4067        }
4068
4069        TABLE_NOISY(printf("Search indices: type=%d, name=%d\n", ti, ei));
4070
4071        const Type* const typeConfigs = group->packages[0]->getType(ti);
4072        if (typeConfigs == NULL || typeConfigs->configs.size() <= 0) {
4073            TABLE_NOISY(printf("Expected type structure not found in package %s for idnex %d\n",
4074                               String8(group->name).string(), ti));
4075        }
4076
4077        size_t NTC = typeConfigs->configs.size();
4078        for (size_t tci=0; tci<NTC; tci++) {
4079            const ResTable_type* const ty = typeConfigs->configs[tci];
4080            const uint32_t typeOffset = dtohl(ty->entriesStart);
4081
4082            const uint8_t* const end = ((const uint8_t*)ty) + dtohl(ty->header.size);
4083            const uint32_t* const eindex = (const uint32_t*)
4084                (((const uint8_t*)ty) + dtohs(ty->header.headerSize));
4085
4086            const size_t NE = dtohl(ty->entryCount);
4087            for (size_t i=0; i<NE; i++) {
4088                uint32_t offset = dtohl(eindex[i]);
4089                if (offset == ResTable_type::NO_ENTRY) {
4090                    continue;
4091                }
4092
4093                offset += typeOffset;
4094
4095                if (offset > (dtohl(ty->header.size)-sizeof(ResTable_entry))) {
4096                    ALOGW("ResTable_entry at %d is beyond type chunk data %d",
4097                         offset, dtohl(ty->header.size));
4098                    return 0;
4099                }
4100                if ((offset&0x3) != 0) {
4101                    ALOGW("ResTable_entry at %d (pkg=%d type=%d ent=%d) is not on an integer boundary when looking for %s:%s/%s",
4102                         (int)offset, (int)group->id, (int)ti+1, (int)i,
4103                         String8(package, packageLen).string(),
4104                         String8(type, typeLen).string(),
4105                         String8(name, nameLen).string());
4106                    return 0;
4107                }
4108
4109                const ResTable_entry* const entry = (const ResTable_entry*)
4110                    (((const uint8_t*)ty) + offset);
4111                if (dtohs(entry->size) < sizeof(*entry)) {
4112                    ALOGW("ResTable_entry size %d is too small", dtohs(entry->size));
4113                    return BAD_TYPE;
4114                }
4115
4116                TABLE_SUPER_NOISY(printf("Looking at entry #%d: want str %d, have %d\n",
4117                                         i, ei, dtohl(entry->key.index)));
4118                if (dtohl(entry->key.index) == (size_t)ei) {
4119                    if (outTypeSpecFlags) {
4120                        *outTypeSpecFlags = typeConfigs->typeSpecFlags[i];
4121                        if (fakePublic) {
4122                            *outTypeSpecFlags |= ResTable_typeSpec::SPEC_PUBLIC;
4123                        }
4124                    }
4125                    return Res_MAKEID(group->id-1, ti, i);
4126                }
4127            }
4128        }
4129    }
4130
4131    return 0;
4132}
4133
4134bool ResTable::expandResourceRef(const uint16_t* refStr, size_t refLen,
4135                                 String16* outPackage,
4136                                 String16* outType,
4137                                 String16* outName,
4138                                 const String16* defType,
4139                                 const String16* defPackage,
4140                                 const char** outErrorMsg,
4141                                 bool* outPublicOnly)
4142{
4143    const char16_t* packageEnd = NULL;
4144    const char16_t* typeEnd = NULL;
4145    const char16_t* p = refStr;
4146    const char16_t* const end = p + refLen;
4147    while (p < end) {
4148        if (*p == ':') packageEnd = p;
4149        else if (*p == '/') {
4150            typeEnd = p;
4151            break;
4152        }
4153        p++;
4154    }
4155    p = refStr;
4156    if (*p == '@') p++;
4157
4158    if (outPublicOnly != NULL) {
4159        *outPublicOnly = true;
4160    }
4161    if (*p == '*') {
4162        p++;
4163        if (outPublicOnly != NULL) {
4164            *outPublicOnly = false;
4165        }
4166    }
4167
4168    if (packageEnd) {
4169        *outPackage = String16(p, packageEnd-p);
4170        p = packageEnd+1;
4171    } else {
4172        if (!defPackage) {
4173            if (outErrorMsg) {
4174                *outErrorMsg = "No resource package specified";
4175            }
4176            return false;
4177        }
4178        *outPackage = *defPackage;
4179    }
4180    if (typeEnd) {
4181        *outType = String16(p, typeEnd-p);
4182        p = typeEnd+1;
4183    } else {
4184        if (!defType) {
4185            if (outErrorMsg) {
4186                *outErrorMsg = "No resource type specified";
4187            }
4188            return false;
4189        }
4190        *outType = *defType;
4191    }
4192    *outName = String16(p, end-p);
4193    if(**outPackage == 0) {
4194        if(outErrorMsg) {
4195            *outErrorMsg = "Resource package cannot be an empty string";
4196        }
4197        return false;
4198    }
4199    if(**outType == 0) {
4200        if(outErrorMsg) {
4201            *outErrorMsg = "Resource type cannot be an empty string";
4202        }
4203        return false;
4204    }
4205    if(**outName == 0) {
4206        if(outErrorMsg) {
4207            *outErrorMsg = "Resource id cannot be an empty string";
4208        }
4209        return false;
4210    }
4211    return true;
4212}
4213
4214static uint32_t get_hex(char c, bool* outError)
4215{
4216    if (c >= '0' && c <= '9') {
4217        return c - '0';
4218    } else if (c >= 'a' && c <= 'f') {
4219        return c - 'a' + 0xa;
4220    } else if (c >= 'A' && c <= 'F') {
4221        return c - 'A' + 0xa;
4222    }
4223    *outError = true;
4224    return 0;
4225}
4226
4227struct unit_entry
4228{
4229    const char* name;
4230    size_t len;
4231    uint8_t type;
4232    uint32_t unit;
4233    float scale;
4234};
4235
4236static const unit_entry unitNames[] = {
4237    { "px", strlen("px"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_PX, 1.0f },
4238    { "dip", strlen("dip"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_DIP, 1.0f },
4239    { "dp", strlen("dp"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_DIP, 1.0f },
4240    { "sp", strlen("sp"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_SP, 1.0f },
4241    { "pt", strlen("pt"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_PT, 1.0f },
4242    { "in", strlen("in"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_IN, 1.0f },
4243    { "mm", strlen("mm"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_MM, 1.0f },
4244    { "%", strlen("%"), Res_value::TYPE_FRACTION, Res_value::COMPLEX_UNIT_FRACTION, 1.0f/100 },
4245    { "%p", strlen("%p"), Res_value::TYPE_FRACTION, Res_value::COMPLEX_UNIT_FRACTION_PARENT, 1.0f/100 },
4246    { NULL, 0, 0, 0, 0 }
4247};
4248
4249static bool parse_unit(const char* str, Res_value* outValue,
4250                       float* outScale, const char** outEnd)
4251{
4252    const char* end = str;
4253    while (*end != 0 && !isspace((unsigned char)*end)) {
4254        end++;
4255    }
4256    const size_t len = end-str;
4257
4258    const char* realEnd = end;
4259    while (*realEnd != 0 && isspace((unsigned char)*realEnd)) {
4260        realEnd++;
4261    }
4262    if (*realEnd != 0) {
4263        return false;
4264    }
4265
4266    const unit_entry* cur = unitNames;
4267    while (cur->name) {
4268        if (len == cur->len && strncmp(cur->name, str, len) == 0) {
4269            outValue->dataType = cur->type;
4270            outValue->data = cur->unit << Res_value::COMPLEX_UNIT_SHIFT;
4271            *outScale = cur->scale;
4272            *outEnd = end;
4273            //printf("Found unit %s for %s\n", cur->name, str);
4274            return true;
4275        }
4276        cur++;
4277    }
4278
4279    return false;
4280}
4281
4282
4283bool ResTable::stringToInt(const char16_t* s, size_t len, Res_value* outValue)
4284{
4285    while (len > 0 && isspace16(*s)) {
4286        s++;
4287        len--;
4288    }
4289
4290    if (len <= 0) {
4291        return false;
4292    }
4293
4294    size_t i = 0;
4295    int32_t val = 0;
4296    bool neg = false;
4297
4298    if (*s == '-') {
4299        neg = true;
4300        i++;
4301    }
4302
4303    if (s[i] < '0' || s[i] > '9') {
4304        return false;
4305    }
4306
4307    // Decimal or hex?
4308    if (s[i] == '0' && s[i+1] == 'x') {
4309        if (outValue)
4310            outValue->dataType = outValue->TYPE_INT_HEX;
4311        i += 2;
4312        bool error = false;
4313        while (i < len && !error) {
4314            val = (val*16) + get_hex(s[i], &error);
4315            i++;
4316        }
4317        if (error) {
4318            return false;
4319        }
4320    } else {
4321        if (outValue)
4322            outValue->dataType = outValue->TYPE_INT_DEC;
4323        while (i < len) {
4324            if (s[i] < '0' || s[i] > '9') {
4325                return false;
4326            }
4327            val = (val*10) + s[i]-'0';
4328            i++;
4329        }
4330    }
4331
4332    if (neg) val = -val;
4333
4334    while (i < len && isspace16(s[i])) {
4335        i++;
4336    }
4337
4338    if (i == len) {
4339        if (outValue)
4340            outValue->data = val;
4341        return true;
4342    }
4343
4344    return false;
4345}
4346
4347bool ResTable::stringToFloat(const char16_t* s, size_t len, Res_value* outValue)
4348{
4349    while (len > 0 && isspace16(*s)) {
4350        s++;
4351        len--;
4352    }
4353
4354    if (len <= 0) {
4355        return false;
4356    }
4357
4358    char buf[128];
4359    int i=0;
4360    while (len > 0 && *s != 0 && i < 126) {
4361        if (*s > 255) {
4362            return false;
4363        }
4364        buf[i++] = *s++;
4365        len--;
4366    }
4367
4368    if (len > 0) {
4369        return false;
4370    }
4371    if (buf[0] < '0' && buf[0] > '9' && buf[0] != '.') {
4372        return false;
4373    }
4374
4375    buf[i] = 0;
4376    const char* end;
4377    float f = strtof(buf, (char**)&end);
4378
4379    if (*end != 0 && !isspace((unsigned char)*end)) {
4380        // Might be a unit...
4381        float scale;
4382        if (parse_unit(end, outValue, &scale, &end)) {
4383            f *= scale;
4384            const bool neg = f < 0;
4385            if (neg) f = -f;
4386            uint64_t bits = (uint64_t)(f*(1<<23)+.5f);
4387            uint32_t radix;
4388            uint32_t shift;
4389            if ((bits&0x7fffff) == 0) {
4390                // Always use 23p0 if there is no fraction, just to make
4391                // things easier to read.
4392                radix = Res_value::COMPLEX_RADIX_23p0;
4393                shift = 23;
4394            } else if ((bits&0xffffffffff800000LL) == 0) {
4395                // Magnitude is zero -- can fit in 0 bits of precision.
4396                radix = Res_value::COMPLEX_RADIX_0p23;
4397                shift = 0;
4398            } else if ((bits&0xffffffff80000000LL) == 0) {
4399                // Magnitude can fit in 8 bits of precision.
4400                radix = Res_value::COMPLEX_RADIX_8p15;
4401                shift = 8;
4402            } else if ((bits&0xffffff8000000000LL) == 0) {
4403                // Magnitude can fit in 16 bits of precision.
4404                radix = Res_value::COMPLEX_RADIX_16p7;
4405                shift = 16;
4406            } else {
4407                // Magnitude needs entire range, so no fractional part.
4408                radix = Res_value::COMPLEX_RADIX_23p0;
4409                shift = 23;
4410            }
4411            int32_t mantissa = (int32_t)(
4412                (bits>>shift) & Res_value::COMPLEX_MANTISSA_MASK);
4413            if (neg) {
4414                mantissa = (-mantissa) & Res_value::COMPLEX_MANTISSA_MASK;
4415            }
4416            outValue->data |=
4417                (radix<<Res_value::COMPLEX_RADIX_SHIFT)
4418                | (mantissa<<Res_value::COMPLEX_MANTISSA_SHIFT);
4419            //printf("Input value: %f 0x%016Lx, mult: %f, radix: %d, shift: %d, final: 0x%08x\n",
4420            //       f * (neg ? -1 : 1), bits, f*(1<<23),
4421            //       radix, shift, outValue->data);
4422            return true;
4423        }
4424        return false;
4425    }
4426
4427    while (*end != 0 && isspace((unsigned char)*end)) {
4428        end++;
4429    }
4430
4431    if (*end == 0) {
4432        if (outValue) {
4433            outValue->dataType = outValue->TYPE_FLOAT;
4434            *(float*)(&outValue->data) = f;
4435            return true;
4436        }
4437    }
4438
4439    return false;
4440}
4441
4442bool ResTable::stringToValue(Res_value* outValue, String16* outString,
4443                             const char16_t* s, size_t len,
4444                             bool preserveSpaces, bool coerceType,
4445                             uint32_t attrID,
4446                             const String16* defType,
4447                             const String16* defPackage,
4448                             Accessor* accessor,
4449                             void* accessorCookie,
4450                             uint32_t attrType,
4451                             bool enforcePrivate) const
4452{
4453    bool localizationSetting = accessor != NULL && accessor->getLocalizationSetting();
4454    const char* errorMsg = NULL;
4455
4456    outValue->size = sizeof(Res_value);
4457    outValue->res0 = 0;
4458
4459    // First strip leading/trailing whitespace.  Do this before handling
4460    // escapes, so they can be used to force whitespace into the string.
4461    if (!preserveSpaces) {
4462        while (len > 0 && isspace16(*s)) {
4463            s++;
4464            len--;
4465        }
4466        while (len > 0 && isspace16(s[len-1])) {
4467            len--;
4468        }
4469        // If the string ends with '\', then we keep the space after it.
4470        if (len > 0 && s[len-1] == '\\' && s[len] != 0) {
4471            len++;
4472        }
4473    }
4474
4475    //printf("Value for: %s\n", String8(s, len).string());
4476
4477    uint32_t l10nReq = ResTable_map::L10N_NOT_REQUIRED;
4478    uint32_t attrMin = 0x80000000, attrMax = 0x7fffffff;
4479    bool fromAccessor = false;
4480    if (attrID != 0 && !Res_INTERNALID(attrID)) {
4481        const ssize_t p = getResourcePackageIndex(attrID);
4482        const bag_entry* bag;
4483        ssize_t cnt = p >= 0 ? lockBag(attrID, &bag) : -1;
4484        //printf("For attr 0x%08x got bag of %d\n", attrID, cnt);
4485        if (cnt >= 0) {
4486            while (cnt > 0) {
4487                //printf("Entry 0x%08x = 0x%08x\n", bag->map.name.ident, bag->map.value.data);
4488                switch (bag->map.name.ident) {
4489                case ResTable_map::ATTR_TYPE:
4490                    attrType = bag->map.value.data;
4491                    break;
4492                case ResTable_map::ATTR_MIN:
4493                    attrMin = bag->map.value.data;
4494                    break;
4495                case ResTable_map::ATTR_MAX:
4496                    attrMax = bag->map.value.data;
4497                    break;
4498                case ResTable_map::ATTR_L10N:
4499                    l10nReq = bag->map.value.data;
4500                    break;
4501                }
4502                bag++;
4503                cnt--;
4504            }
4505            unlockBag(bag);
4506        } else if (accessor && accessor->getAttributeType(attrID, &attrType)) {
4507            fromAccessor = true;
4508            if (attrType == ResTable_map::TYPE_ENUM
4509                    || attrType == ResTable_map::TYPE_FLAGS
4510                    || attrType == ResTable_map::TYPE_INTEGER) {
4511                accessor->getAttributeMin(attrID, &attrMin);
4512                accessor->getAttributeMax(attrID, &attrMax);
4513            }
4514            if (localizationSetting) {
4515                l10nReq = accessor->getAttributeL10N(attrID);
4516            }
4517        }
4518    }
4519
4520    const bool canStringCoerce =
4521        coerceType && (attrType&ResTable_map::TYPE_STRING) != 0;
4522
4523    if (*s == '@') {
4524        outValue->dataType = outValue->TYPE_REFERENCE;
4525
4526        // Note: we don't check attrType here because the reference can
4527        // be to any other type; we just need to count on the client making
4528        // sure the referenced type is correct.
4529
4530        //printf("Looking up ref: %s\n", String8(s, len).string());
4531
4532        // It's a reference!
4533        if (len == 5 && s[1]=='n' && s[2]=='u' && s[3]=='l' && s[4]=='l') {
4534            outValue->data = 0;
4535            return true;
4536        } else {
4537            bool createIfNotFound = false;
4538            const char16_t* resourceRefName;
4539            int resourceNameLen;
4540            if (len > 2 && s[1] == '+') {
4541                createIfNotFound = true;
4542                resourceRefName = s + 2;
4543                resourceNameLen = len - 2;
4544            } else if (len > 2 && s[1] == '*') {
4545                enforcePrivate = false;
4546                resourceRefName = s + 2;
4547                resourceNameLen = len - 2;
4548            } else {
4549                createIfNotFound = false;
4550                resourceRefName = s + 1;
4551                resourceNameLen = len - 1;
4552            }
4553            String16 package, type, name;
4554            if (!expandResourceRef(resourceRefName,resourceNameLen, &package, &type, &name,
4555                                   defType, defPackage, &errorMsg)) {
4556                if (accessor != NULL) {
4557                    accessor->reportError(accessorCookie, errorMsg);
4558                }
4559                return false;
4560            }
4561
4562            uint32_t specFlags = 0;
4563            uint32_t rid = identifierForName(name.string(), name.size(), type.string(),
4564                    type.size(), package.string(), package.size(), &specFlags);
4565            if (rid != 0) {
4566                if (enforcePrivate) {
4567                    if ((specFlags&ResTable_typeSpec::SPEC_PUBLIC) == 0) {
4568                        if (accessor != NULL) {
4569                            accessor->reportError(accessorCookie, "Resource is not public.");
4570                        }
4571                        return false;
4572                    }
4573                }
4574                if (!accessor) {
4575                    outValue->data = rid;
4576                    return true;
4577                }
4578                rid = Res_MAKEID(
4579                    accessor->getRemappedPackage(Res_GETPACKAGE(rid)),
4580                    Res_GETTYPE(rid), Res_GETENTRY(rid));
4581                TABLE_NOISY(printf("Incl %s:%s/%s: 0x%08x\n",
4582                       String8(package).string(), String8(type).string(),
4583                       String8(name).string(), rid));
4584                outValue->data = rid;
4585                return true;
4586            }
4587
4588            if (accessor) {
4589                uint32_t rid = accessor->getCustomResourceWithCreation(package, type, name,
4590                                                                       createIfNotFound);
4591                if (rid != 0) {
4592                    TABLE_NOISY(printf("Pckg %s:%s/%s: 0x%08x\n",
4593                           String8(package).string(), String8(type).string(),
4594                           String8(name).string(), rid));
4595                    outValue->data = rid;
4596                    return true;
4597                }
4598            }
4599        }
4600
4601        if (accessor != NULL) {
4602            accessor->reportError(accessorCookie, "No resource found that matches the given name");
4603        }
4604        return false;
4605    }
4606
4607    // if we got to here, and localization is required and it's not a reference,
4608    // complain and bail.
4609    if (l10nReq == ResTable_map::L10N_SUGGESTED) {
4610        if (localizationSetting) {
4611            if (accessor != NULL) {
4612                accessor->reportError(accessorCookie, "This attribute must be localized.");
4613            }
4614        }
4615    }
4616
4617    if (*s == '#') {
4618        // It's a color!  Convert to an integer of the form 0xaarrggbb.
4619        uint32_t color = 0;
4620        bool error = false;
4621        if (len == 4) {
4622            outValue->dataType = outValue->TYPE_INT_COLOR_RGB4;
4623            color |= 0xFF000000;
4624            color |= get_hex(s[1], &error) << 20;
4625            color |= get_hex(s[1], &error) << 16;
4626            color |= get_hex(s[2], &error) << 12;
4627            color |= get_hex(s[2], &error) << 8;
4628            color |= get_hex(s[3], &error) << 4;
4629            color |= get_hex(s[3], &error);
4630        } else if (len == 5) {
4631            outValue->dataType = outValue->TYPE_INT_COLOR_ARGB4;
4632            color |= get_hex(s[1], &error) << 28;
4633            color |= get_hex(s[1], &error) << 24;
4634            color |= get_hex(s[2], &error) << 20;
4635            color |= get_hex(s[2], &error) << 16;
4636            color |= get_hex(s[3], &error) << 12;
4637            color |= get_hex(s[3], &error) << 8;
4638            color |= get_hex(s[4], &error) << 4;
4639            color |= get_hex(s[4], &error);
4640        } else if (len == 7) {
4641            outValue->dataType = outValue->TYPE_INT_COLOR_RGB8;
4642            color |= 0xFF000000;
4643            color |= get_hex(s[1], &error) << 20;
4644            color |= get_hex(s[2], &error) << 16;
4645            color |= get_hex(s[3], &error) << 12;
4646            color |= get_hex(s[4], &error) << 8;
4647            color |= get_hex(s[5], &error) << 4;
4648            color |= get_hex(s[6], &error);
4649        } else if (len == 9) {
4650            outValue->dataType = outValue->TYPE_INT_COLOR_ARGB8;
4651            color |= get_hex(s[1], &error) << 28;
4652            color |= get_hex(s[2], &error) << 24;
4653            color |= get_hex(s[3], &error) << 20;
4654            color |= get_hex(s[4], &error) << 16;
4655            color |= get_hex(s[5], &error) << 12;
4656            color |= get_hex(s[6], &error) << 8;
4657            color |= get_hex(s[7], &error) << 4;
4658            color |= get_hex(s[8], &error);
4659        } else {
4660            error = true;
4661        }
4662        if (!error) {
4663            if ((attrType&ResTable_map::TYPE_COLOR) == 0) {
4664                if (!canStringCoerce) {
4665                    if (accessor != NULL) {
4666                        accessor->reportError(accessorCookie,
4667                                "Color types not allowed");
4668                    }
4669                    return false;
4670                }
4671            } else {
4672                outValue->data = color;
4673                //printf("Color input=%s, output=0x%x\n", String8(s, len).string(), color);
4674                return true;
4675            }
4676        } else {
4677            if ((attrType&ResTable_map::TYPE_COLOR) != 0) {
4678                if (accessor != NULL) {
4679                    accessor->reportError(accessorCookie, "Color value not valid --"
4680                            " must be #rgb, #argb, #rrggbb, or #aarrggbb");
4681                }
4682                #if 0
4683                fprintf(stderr, "%s: Color ID %s value %s is not valid\n",
4684                        "Resource File", //(const char*)in->getPrintableSource(),
4685                        String8(*curTag).string(),
4686                        String8(s, len).string());
4687                #endif
4688                return false;
4689            }
4690        }
4691    }
4692
4693    if (*s == '?') {
4694        outValue->dataType = outValue->TYPE_ATTRIBUTE;
4695
4696        // Note: we don't check attrType here because the reference can
4697        // be to any other type; we just need to count on the client making
4698        // sure the referenced type is correct.
4699
4700        //printf("Looking up attr: %s\n", String8(s, len).string());
4701
4702        static const String16 attr16("attr");
4703        String16 package, type, name;
4704        if (!expandResourceRef(s+1, len-1, &package, &type, &name,
4705                               &attr16, defPackage, &errorMsg)) {
4706            if (accessor != NULL) {
4707                accessor->reportError(accessorCookie, errorMsg);
4708            }
4709            return false;
4710        }
4711
4712        //printf("Pkg: %s, Type: %s, Name: %s\n",
4713        //       String8(package).string(), String8(type).string(),
4714        //       String8(name).string());
4715        uint32_t specFlags = 0;
4716        uint32_t rid =
4717            identifierForName(name.string(), name.size(),
4718                              type.string(), type.size(),
4719                              package.string(), package.size(), &specFlags);
4720        if (rid != 0) {
4721            if (enforcePrivate) {
4722                if ((specFlags&ResTable_typeSpec::SPEC_PUBLIC) == 0) {
4723                    if (accessor != NULL) {
4724                        accessor->reportError(accessorCookie, "Attribute is not public.");
4725                    }
4726                    return false;
4727                }
4728            }
4729            if (!accessor) {
4730                outValue->data = rid;
4731                return true;
4732            }
4733            rid = Res_MAKEID(
4734                accessor->getRemappedPackage(Res_GETPACKAGE(rid)),
4735                Res_GETTYPE(rid), Res_GETENTRY(rid));
4736            //printf("Incl %s:%s/%s: 0x%08x\n",
4737            //       String8(package).string(), String8(type).string(),
4738            //       String8(name).string(), rid);
4739            outValue->data = rid;
4740            return true;
4741        }
4742
4743        if (accessor) {
4744            uint32_t rid = accessor->getCustomResource(package, type, name);
4745            if (rid != 0) {
4746                //printf("Mine %s:%s/%s: 0x%08x\n",
4747                //       String8(package).string(), String8(type).string(),
4748                //       String8(name).string(), rid);
4749                outValue->data = rid;
4750                return true;
4751            }
4752        }
4753
4754        if (accessor != NULL) {
4755            accessor->reportError(accessorCookie, "No resource found that matches the given name");
4756        }
4757        return false;
4758    }
4759
4760    if (stringToInt(s, len, outValue)) {
4761        if ((attrType&ResTable_map::TYPE_INTEGER) == 0) {
4762            // If this type does not allow integers, but does allow floats,
4763            // fall through on this error case because the float type should
4764            // be able to accept any integer value.
4765            if (!canStringCoerce && (attrType&ResTable_map::TYPE_FLOAT) == 0) {
4766                if (accessor != NULL) {
4767                    accessor->reportError(accessorCookie, "Integer types not allowed");
4768                }
4769                return false;
4770            }
4771        } else {
4772            if (((int32_t)outValue->data) < ((int32_t)attrMin)
4773                    || ((int32_t)outValue->data) > ((int32_t)attrMax)) {
4774                if (accessor != NULL) {
4775                    accessor->reportError(accessorCookie, "Integer value out of range");
4776                }
4777                return false;
4778            }
4779            return true;
4780        }
4781    }
4782
4783    if (stringToFloat(s, len, outValue)) {
4784        if (outValue->dataType == Res_value::TYPE_DIMENSION) {
4785            if ((attrType&ResTable_map::TYPE_DIMENSION) != 0) {
4786                return true;
4787            }
4788            if (!canStringCoerce) {
4789                if (accessor != NULL) {
4790                    accessor->reportError(accessorCookie, "Dimension types not allowed");
4791                }
4792                return false;
4793            }
4794        } else if (outValue->dataType == Res_value::TYPE_FRACTION) {
4795            if ((attrType&ResTable_map::TYPE_FRACTION) != 0) {
4796                return true;
4797            }
4798            if (!canStringCoerce) {
4799                if (accessor != NULL) {
4800                    accessor->reportError(accessorCookie, "Fraction types not allowed");
4801                }
4802                return false;
4803            }
4804        } else if ((attrType&ResTable_map::TYPE_FLOAT) == 0) {
4805            if (!canStringCoerce) {
4806                if (accessor != NULL) {
4807                    accessor->reportError(accessorCookie, "Float types not allowed");
4808                }
4809                return false;
4810            }
4811        } else {
4812            return true;
4813        }
4814    }
4815
4816    if (len == 4) {
4817        if ((s[0] == 't' || s[0] == 'T') &&
4818            (s[1] == 'r' || s[1] == 'R') &&
4819            (s[2] == 'u' || s[2] == 'U') &&
4820            (s[3] == 'e' || s[3] == 'E')) {
4821            if ((attrType&ResTable_map::TYPE_BOOLEAN) == 0) {
4822                if (!canStringCoerce) {
4823                    if (accessor != NULL) {
4824                        accessor->reportError(accessorCookie, "Boolean types not allowed");
4825                    }
4826                    return false;
4827                }
4828            } else {
4829                outValue->dataType = outValue->TYPE_INT_BOOLEAN;
4830                outValue->data = (uint32_t)-1;
4831                return true;
4832            }
4833        }
4834    }
4835
4836    if (len == 5) {
4837        if ((s[0] == 'f' || s[0] == 'F') &&
4838            (s[1] == 'a' || s[1] == 'A') &&
4839            (s[2] == 'l' || s[2] == 'L') &&
4840            (s[3] == 's' || s[3] == 'S') &&
4841            (s[4] == 'e' || s[4] == 'E')) {
4842            if ((attrType&ResTable_map::TYPE_BOOLEAN) == 0) {
4843                if (!canStringCoerce) {
4844                    if (accessor != NULL) {
4845                        accessor->reportError(accessorCookie, "Boolean types not allowed");
4846                    }
4847                    return false;
4848                }
4849            } else {
4850                outValue->dataType = outValue->TYPE_INT_BOOLEAN;
4851                outValue->data = 0;
4852                return true;
4853            }
4854        }
4855    }
4856
4857    if ((attrType&ResTable_map::TYPE_ENUM) != 0) {
4858        const ssize_t p = getResourcePackageIndex(attrID);
4859        const bag_entry* bag;
4860        ssize_t cnt = p >= 0 ? lockBag(attrID, &bag) : -1;
4861        //printf("Got %d for enum\n", cnt);
4862        if (cnt >= 0) {
4863            resource_name rname;
4864            while (cnt > 0) {
4865                if (!Res_INTERNALID(bag->map.name.ident)) {
4866                    //printf("Trying attr #%08x\n", bag->map.name.ident);
4867                    if (getResourceName(bag->map.name.ident, false, &rname)) {
4868                        #if 0
4869                        printf("Matching %s against %s (0x%08x)\n",
4870                               String8(s, len).string(),
4871                               String8(rname.name, rname.nameLen).string(),
4872                               bag->map.name.ident);
4873                        #endif
4874                        if (strzcmp16(s, len, rname.name, rname.nameLen) == 0) {
4875                            outValue->dataType = bag->map.value.dataType;
4876                            outValue->data = bag->map.value.data;
4877                            unlockBag(bag);
4878                            return true;
4879                        }
4880                    }
4881
4882                }
4883                bag++;
4884                cnt--;
4885            }
4886            unlockBag(bag);
4887        }
4888
4889        if (fromAccessor) {
4890            if (accessor->getAttributeEnum(attrID, s, len, outValue)) {
4891                return true;
4892            }
4893        }
4894    }
4895
4896    if ((attrType&ResTable_map::TYPE_FLAGS) != 0) {
4897        const ssize_t p = getResourcePackageIndex(attrID);
4898        const bag_entry* bag;
4899        ssize_t cnt = p >= 0 ? lockBag(attrID, &bag) : -1;
4900        //printf("Got %d for flags\n", cnt);
4901        if (cnt >= 0) {
4902            bool failed = false;
4903            resource_name rname;
4904            outValue->dataType = Res_value::TYPE_INT_HEX;
4905            outValue->data = 0;
4906            const char16_t* end = s + len;
4907            const char16_t* pos = s;
4908            while (pos < end && !failed) {
4909                const char16_t* start = pos;
4910                pos++;
4911                while (pos < end && *pos != '|') {
4912                    pos++;
4913                }
4914                //printf("Looking for: %s\n", String8(start, pos-start).string());
4915                const bag_entry* bagi = bag;
4916                ssize_t i;
4917                for (i=0; i<cnt; i++, bagi++) {
4918                    if (!Res_INTERNALID(bagi->map.name.ident)) {
4919                        //printf("Trying attr #%08x\n", bagi->map.name.ident);
4920                        if (getResourceName(bagi->map.name.ident, false, &rname)) {
4921                            #if 0
4922                            printf("Matching %s against %s (0x%08x)\n",
4923                                   String8(start,pos-start).string(),
4924                                   String8(rname.name, rname.nameLen).string(),
4925                                   bagi->map.name.ident);
4926                            #endif
4927                            if (strzcmp16(start, pos-start, rname.name, rname.nameLen) == 0) {
4928                                outValue->data |= bagi->map.value.data;
4929                                break;
4930                            }
4931                        }
4932                    }
4933                }
4934                if (i >= cnt) {
4935                    // Didn't find this flag identifier.
4936                    failed = true;
4937                }
4938                if (pos < end) {
4939                    pos++;
4940                }
4941            }
4942            unlockBag(bag);
4943            if (!failed) {
4944                //printf("Final flag value: 0x%lx\n", outValue->data);
4945                return true;
4946            }
4947        }
4948
4949
4950        if (fromAccessor) {
4951            if (accessor->getAttributeFlags(attrID, s, len, outValue)) {
4952                //printf("Final flag value: 0x%lx\n", outValue->data);
4953                return true;
4954            }
4955        }
4956    }
4957
4958    if ((attrType&ResTable_map::TYPE_STRING) == 0) {
4959        if (accessor != NULL) {
4960            accessor->reportError(accessorCookie, "String types not allowed");
4961        }
4962        return false;
4963    }
4964
4965    // Generic string handling...
4966    outValue->dataType = outValue->TYPE_STRING;
4967    if (outString) {
4968        bool failed = collectString(outString, s, len, preserveSpaces, &errorMsg);
4969        if (accessor != NULL) {
4970            accessor->reportError(accessorCookie, errorMsg);
4971        }
4972        return failed;
4973    }
4974
4975    return true;
4976}
4977
4978bool ResTable::collectString(String16* outString,
4979                             const char16_t* s, size_t len,
4980                             bool preserveSpaces,
4981                             const char** outErrorMsg,
4982                             bool append)
4983{
4984    String16 tmp;
4985
4986    char quoted = 0;
4987    const char16_t* p = s;
4988    while (p < (s+len)) {
4989        while (p < (s+len)) {
4990            const char16_t c = *p;
4991            if (c == '\\') {
4992                break;
4993            }
4994            if (!preserveSpaces) {
4995                if (quoted == 0 && isspace16(c)
4996                    && (c != ' ' || isspace16(*(p+1)))) {
4997                    break;
4998                }
4999                if (c == '"' && (quoted == 0 || quoted == '"')) {
5000                    break;
5001                }
5002                if (c == '\'' && (quoted == 0 || quoted == '\'')) {
5003                    /*
5004                     * In practice, when people write ' instead of \'
5005                     * in a string, they are doing it by accident
5006                     * instead of really meaning to use ' as a quoting
5007                     * character.  Warn them so they don't lose it.
5008                     */
5009                    if (outErrorMsg) {
5010                        *outErrorMsg = "Apostrophe not preceded by \\";
5011                    }
5012                    return false;
5013                }
5014            }
5015            p++;
5016        }
5017        if (p < (s+len)) {
5018            if (p > s) {
5019                tmp.append(String16(s, p-s));
5020            }
5021            if (!preserveSpaces && (*p == '"' || *p == '\'')) {
5022                if (quoted == 0) {
5023                    quoted = *p;
5024                } else {
5025                    quoted = 0;
5026                }
5027                p++;
5028            } else if (!preserveSpaces && isspace16(*p)) {
5029                // Space outside of a quote -- consume all spaces and
5030                // leave a single plain space char.
5031                tmp.append(String16(" "));
5032                p++;
5033                while (p < (s+len) && isspace16(*p)) {
5034                    p++;
5035                }
5036            } else if (*p == '\\') {
5037                p++;
5038                if (p < (s+len)) {
5039                    switch (*p) {
5040                    case 't':
5041                        tmp.append(String16("\t"));
5042                        break;
5043                    case 'n':
5044                        tmp.append(String16("\n"));
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 '\\':
5062                        tmp.append(String16("\\"));
5063                        break;
5064                    case 'u':
5065                    {
5066                        char16_t chr = 0;
5067                        int i = 0;
5068                        while (i < 4 && p[1] != 0) {
5069                            p++;
5070                            i++;
5071                            int c;
5072                            if (*p >= '0' && *p <= '9') {
5073                                c = *p - '0';
5074                            } else if (*p >= 'a' && *p <= 'f') {
5075                                c = *p - 'a' + 10;
5076                            } else if (*p >= 'A' && *p <= 'F') {
5077                                c = *p - 'A' + 10;
5078                            } else {
5079                                if (outErrorMsg) {
5080                                    *outErrorMsg = "Bad character in \\u unicode escape sequence";
5081                                }
5082                                return false;
5083                            }
5084                            chr = (chr<<4) | c;
5085                        }
5086                        tmp.append(String16(&chr, 1));
5087                    } break;
5088                    default:
5089                        // ignore unknown escape chars.
5090                        break;
5091                    }
5092                    p++;
5093                }
5094            }
5095            len -= (p-s);
5096            s = p;
5097        }
5098    }
5099
5100    if (tmp.size() != 0) {
5101        if (len > 0) {
5102            tmp.append(String16(s, len));
5103        }
5104        if (append) {
5105            outString->append(tmp);
5106        } else {
5107            outString->setTo(tmp);
5108        }
5109    } else {
5110        if (append) {
5111            outString->append(String16(s, len));
5112        } else {
5113            outString->setTo(s, len);
5114        }
5115    }
5116
5117    return true;
5118}
5119
5120size_t ResTable::getBasePackageCount() const
5121{
5122    if (mError != NO_ERROR) {
5123        return 0;
5124    }
5125    return mPackageGroups.size();
5126}
5127
5128const char16_t* ResTable::getBasePackageName(size_t idx) const
5129{
5130    if (mError != NO_ERROR) {
5131        return 0;
5132    }
5133    LOG_FATAL_IF(idx >= mPackageGroups.size(),
5134                 "Requested package index %d past package count %d",
5135                 (int)idx, (int)mPackageGroups.size());
5136    return mPackageGroups[idx]->name.string();
5137}
5138
5139uint32_t ResTable::getBasePackageId(size_t idx) const
5140{
5141    if (mError != NO_ERROR) {
5142        return 0;
5143    }
5144    LOG_FATAL_IF(idx >= mPackageGroups.size(),
5145                 "Requested package index %d past package count %d",
5146                 (int)idx, (int)mPackageGroups.size());
5147    return mPackageGroups[idx]->id;
5148}
5149
5150size_t ResTable::getTableCount() const
5151{
5152    return mHeaders.size();
5153}
5154
5155const ResStringPool* ResTable::getTableStringBlock(size_t index) const
5156{
5157    return &mHeaders[index]->values;
5158}
5159
5160int32_t ResTable::getTableCookie(size_t index) const
5161{
5162    return mHeaders[index]->cookie;
5163}
5164
5165void ResTable::getConfigurations(Vector<ResTable_config>* configs) const
5166{
5167    const size_t I = mPackageGroups.size();
5168    for (size_t i=0; i<I; i++) {
5169        const PackageGroup* packageGroup = mPackageGroups[i];
5170        const size_t J = packageGroup->packages.size();
5171        for (size_t j=0; j<J; j++) {
5172            const Package* package = packageGroup->packages[j];
5173            const size_t K = package->types.size();
5174            for (size_t k=0; k<K; k++) {
5175                const Type* type = package->types[k];
5176                if (type == NULL) continue;
5177                const size_t L = type->configs.size();
5178                for (size_t l=0; l<L; l++) {
5179                    const ResTable_type* config = type->configs[l];
5180                    ResTable_config cfg;
5181                    memset(&cfg, 0, sizeof(ResTable_config));
5182                    cfg.copyFromDtoH(config->config);
5183                    // only insert unique
5184                    const size_t M = configs->size();
5185                    size_t m;
5186                    for (m=0; m<M; m++) {
5187                        if (0 == (*configs)[m].compare(cfg)) {
5188                            break;
5189                        }
5190                    }
5191                    // if we didn't find it
5192                    if (m == M) {
5193                        configs->add(cfg);
5194                    }
5195                }
5196            }
5197        }
5198    }
5199}
5200
5201void ResTable::getLocales(Vector<String8>* locales) const
5202{
5203    Vector<ResTable_config> configs;
5204    ALOGV("calling getConfigurations");
5205    getConfigurations(&configs);
5206    ALOGV("called getConfigurations size=%d", (int)configs.size());
5207    const size_t I = configs.size();
5208
5209    char locale[RESTABLE_MAX_LOCALE_LEN];
5210    for (size_t i=0; i<I; i++) {
5211        configs[i].getBcp47Locale(locale);
5212        const size_t J = locales->size();
5213        size_t j;
5214        for (j=0; j<J; j++) {
5215            if (0 == strcmp(locale, (*locales)[j].string())) {
5216                break;
5217            }
5218        }
5219        if (j == J) {
5220            locales->add(String8(locale));
5221        }
5222    }
5223}
5224
5225ssize_t ResTable::getEntry(
5226    const Package* package, int typeIndex, int entryIndex,
5227    const ResTable_config* config,
5228    const ResTable_type** outType, const ResTable_entry** outEntry,
5229    const Type** outTypeClass) const
5230{
5231    ALOGV("Getting entry from package %p\n", package);
5232    const ResTable_package* const pkg = package->package;
5233
5234    const Type* allTypes = package->getType(typeIndex);
5235    ALOGV("allTypes=%p\n", allTypes);
5236    if (allTypes == NULL) {
5237        ALOGV("Skipping entry type index 0x%02x because type is NULL!\n", typeIndex);
5238        return 0;
5239    }
5240
5241    if ((size_t)entryIndex >= allTypes->entryCount) {
5242        ALOGW("getEntry failing because entryIndex %d is beyond type entryCount %d",
5243            entryIndex, (int)allTypes->entryCount);
5244        return BAD_TYPE;
5245    }
5246
5247    const ResTable_type* type = NULL;
5248    uint32_t offset = ResTable_type::NO_ENTRY;
5249    ResTable_config bestConfig;
5250    memset(&bestConfig, 0, sizeof(bestConfig)); // make the compiler shut up
5251
5252    const size_t NT = allTypes->configs.size();
5253    for (size_t i=0; i<NT; i++) {
5254        const ResTable_type* const thisType = allTypes->configs[i];
5255        if (thisType == NULL) continue;
5256
5257        ResTable_config thisConfig;
5258        thisConfig.copyFromDtoH(thisType->config);
5259
5260        TABLE_GETENTRY(ALOGI("Match entry 0x%x in type 0x%x (sz 0x%x): %s\n",
5261                           entryIndex, typeIndex+1, dtohl(thisType->config.size),
5262                           thisConfig.toString().string()));
5263
5264        // Check to make sure this one is valid for the current parameters.
5265        if (config && !thisConfig.match(*config)) {
5266            TABLE_GETENTRY(ALOGI("Does not match config!\n"));
5267            continue;
5268        }
5269
5270        // Check if there is the desired entry in this type.
5271
5272        const uint8_t* const end = ((const uint8_t*)thisType)
5273            + dtohl(thisType->header.size);
5274        const uint32_t* const eindex = (const uint32_t*)
5275            (((const uint8_t*)thisType) + dtohs(thisType->header.headerSize));
5276
5277        uint32_t thisOffset = dtohl(eindex[entryIndex]);
5278        if (thisOffset == ResTable_type::NO_ENTRY) {
5279            TABLE_GETENTRY(ALOGI("Skipping because it is not defined!\n"));
5280            continue;
5281        }
5282
5283        if (type != NULL) {
5284            // Check if this one is less specific than the last found.  If so,
5285            // we will skip it.  We check starting with things we most care
5286            // about to those we least care about.
5287            if (!thisConfig.isBetterThan(bestConfig, config)) {
5288                TABLE_GETENTRY(ALOGI("This config is worse than last!\n"));
5289                continue;
5290            }
5291        }
5292
5293        type = thisType;
5294        offset = thisOffset;
5295        bestConfig = thisConfig;
5296        TABLE_GETENTRY(ALOGI("Best entry so far -- using it!\n"));
5297        if (!config) break;
5298    }
5299
5300    if (type == NULL) {
5301        TABLE_GETENTRY(ALOGI("No value found for requested entry!\n"));
5302        return BAD_INDEX;
5303    }
5304
5305    offset += dtohl(type->entriesStart);
5306    TABLE_NOISY(aout << "Looking in resource table " << package->header->header
5307          << ", typeOff="
5308          << (void*)(((const char*)type)-((const char*)package->header->header))
5309          << ", offset=" << (void*)offset << endl);
5310
5311    if (offset > (dtohl(type->header.size)-sizeof(ResTable_entry))) {
5312        ALOGW("ResTable_entry at 0x%x is beyond type chunk data 0x%x",
5313             offset, dtohl(type->header.size));
5314        return BAD_TYPE;
5315    }
5316    if ((offset&0x3) != 0) {
5317        ALOGW("ResTable_entry at 0x%x is not on an integer boundary",
5318             offset);
5319        return BAD_TYPE;
5320    }
5321
5322    const ResTable_entry* const entry = (const ResTable_entry*)
5323        (((const uint8_t*)type) + offset);
5324    if (dtohs(entry->size) < sizeof(*entry)) {
5325        ALOGW("ResTable_entry size 0x%x is too small", dtohs(entry->size));
5326        return BAD_TYPE;
5327    }
5328
5329    *outType = type;
5330    *outEntry = entry;
5331    if (outTypeClass != NULL) {
5332        *outTypeClass = allTypes;
5333    }
5334    return offset + dtohs(entry->size);
5335}
5336
5337status_t ResTable::parsePackage(const ResTable_package* const pkg,
5338                                const Header* const header, uint32_t idmap_id)
5339{
5340    const uint8_t* base = (const uint8_t*)pkg;
5341    status_t err = validate_chunk(&pkg->header, sizeof(*pkg),
5342                                  header->dataEnd, "ResTable_package");
5343    if (err != NO_ERROR) {
5344        return (mError=err);
5345    }
5346
5347    const uint32_t pkgSize = dtohl(pkg->header.size);
5348
5349    if (dtohl(pkg->typeStrings) >= pkgSize) {
5350        ALOGW("ResTable_package type strings at 0x%x are past chunk size 0x%x.",
5351             dtohl(pkg->typeStrings), pkgSize);
5352        return (mError=BAD_TYPE);
5353    }
5354    if ((dtohl(pkg->typeStrings)&0x3) != 0) {
5355        ALOGW("ResTable_package type strings at 0x%x is not on an integer boundary.",
5356             dtohl(pkg->typeStrings));
5357        return (mError=BAD_TYPE);
5358    }
5359    if (dtohl(pkg->keyStrings) >= pkgSize) {
5360        ALOGW("ResTable_package key strings at 0x%x are past chunk size 0x%x.",
5361             dtohl(pkg->keyStrings), pkgSize);
5362        return (mError=BAD_TYPE);
5363    }
5364    if ((dtohl(pkg->keyStrings)&0x3) != 0) {
5365        ALOGW("ResTable_package key strings at 0x%x is not on an integer boundary.",
5366             dtohl(pkg->keyStrings));
5367        return (mError=BAD_TYPE);
5368    }
5369
5370    Package* package = NULL;
5371    PackageGroup* group = NULL;
5372    uint32_t id = idmap_id != 0 ? idmap_id : dtohl(pkg->id);
5373    // If at this point id == 0, pkg is an overlay package without a
5374    // corresponding idmap. During regular usage, overlay packages are
5375    // always loaded alongside their idmaps, but during idmap creation
5376    // the package is temporarily loaded by itself.
5377    if (id < 256) {
5378
5379        package = new Package(this, header, pkg);
5380        if (package == NULL) {
5381            return (mError=NO_MEMORY);
5382        }
5383
5384        size_t idx = mPackageMap[id];
5385        if (idx == 0) {
5386            idx = mPackageGroups.size()+1;
5387
5388            char16_t tmpName[sizeof(pkg->name)/sizeof(char16_t)];
5389            strcpy16_dtoh(tmpName, pkg->name, sizeof(pkg->name)/sizeof(char16_t));
5390            group = new PackageGroup(this, String16(tmpName), id);
5391            if (group == NULL) {
5392                delete package;
5393                return (mError=NO_MEMORY);
5394            }
5395
5396            err = package->typeStrings.setTo(base+dtohl(pkg->typeStrings),
5397                                           header->dataEnd-(base+dtohl(pkg->typeStrings)));
5398            if (err != NO_ERROR) {
5399                delete group;
5400                delete package;
5401                return (mError=err);
5402            }
5403            err = package->keyStrings.setTo(base+dtohl(pkg->keyStrings),
5404                                          header->dataEnd-(base+dtohl(pkg->keyStrings)));
5405            if (err != NO_ERROR) {
5406                delete group;
5407                delete package;
5408                return (mError=err);
5409            }
5410
5411            err = group->packages.add(package);
5412            if (err < NO_ERROR) {
5413                delete group;
5414                delete package;
5415                return (mError=err);
5416            }
5417            group->basePackage = package;
5418
5419            //printf("Adding new package id %d at index %d\n", id, idx);
5420            err = mPackageGroups.add(group);
5421            if (err < NO_ERROR) {
5422                delete group;
5423                return (mError=err);
5424            }
5425
5426            mPackageMap[id] = (uint8_t)idx;
5427        } else {
5428            group = mPackageGroups.itemAt(idx-1);
5429            if (group == NULL) {
5430                delete package;
5431                return (mError=UNKNOWN_ERROR);
5432            }
5433            err = group->packages.add(package);
5434            if (err < NO_ERROR) {
5435                delete package;
5436                return (mError=err);
5437            }
5438        }
5439    } else {
5440        LOG_ALWAYS_FATAL("Package id out of range");
5441        return NO_ERROR;
5442    }
5443
5444
5445    // Iterate through all chunks.
5446    size_t curPackage = 0;
5447
5448    const ResChunk_header* chunk =
5449        (const ResChunk_header*)(((const uint8_t*)pkg)
5450                                 + dtohs(pkg->header.headerSize));
5451    const uint8_t* endPos = ((const uint8_t*)pkg) + dtohs(pkg->header.size);
5452    while (((const uint8_t*)chunk) <= (endPos-sizeof(ResChunk_header)) &&
5453           ((const uint8_t*)chunk) <= (endPos-dtohl(chunk->size))) {
5454        TABLE_NOISY(ALOGV("PackageChunk: type=0x%x, headerSize=0x%x, size=0x%x, pos=%p\n",
5455                         dtohs(chunk->type), dtohs(chunk->headerSize), dtohl(chunk->size),
5456                         (void*)(((const uint8_t*)chunk) - ((const uint8_t*)header->header))));
5457        const size_t csize = dtohl(chunk->size);
5458        const uint16_t ctype = dtohs(chunk->type);
5459        if (ctype == RES_TABLE_TYPE_SPEC_TYPE) {
5460            const ResTable_typeSpec* typeSpec = (const ResTable_typeSpec*)(chunk);
5461            err = validate_chunk(&typeSpec->header, sizeof(*typeSpec),
5462                                 endPos, "ResTable_typeSpec");
5463            if (err != NO_ERROR) {
5464                return (mError=err);
5465            }
5466
5467            const size_t typeSpecSize = dtohl(typeSpec->header.size);
5468
5469            LOAD_TABLE_NOISY(printf("TypeSpec off %p: type=0x%x, headerSize=0x%x, size=%p\n",
5470                                    (void*)(base-(const uint8_t*)chunk),
5471                                    dtohs(typeSpec->header.type),
5472                                    dtohs(typeSpec->header.headerSize),
5473                                    (void*)typeSize));
5474            // look for block overrun or int overflow when multiplying by 4
5475            if ((dtohl(typeSpec->entryCount) > (INT32_MAX/sizeof(uint32_t))
5476                    || dtohs(typeSpec->header.headerSize)+(sizeof(uint32_t)*dtohl(typeSpec->entryCount))
5477                    > typeSpecSize)) {
5478                ALOGW("ResTable_typeSpec entry index to %p extends beyond chunk end %p.",
5479                     (void*)(dtohs(typeSpec->header.headerSize)
5480                             +(sizeof(uint32_t)*dtohl(typeSpec->entryCount))),
5481                     (void*)typeSpecSize);
5482                return (mError=BAD_TYPE);
5483            }
5484
5485            if (typeSpec->id == 0) {
5486                ALOGW("ResTable_type has an id of 0.");
5487                return (mError=BAD_TYPE);
5488            }
5489
5490            while (package->types.size() < typeSpec->id) {
5491                package->types.add(NULL);
5492            }
5493            Type* t = package->types[typeSpec->id-1];
5494            if (t == NULL) {
5495                t = new Type(header, package, dtohl(typeSpec->entryCount));
5496                package->types.editItemAt(typeSpec->id-1) = t;
5497            } else if (dtohl(typeSpec->entryCount) != t->entryCount) {
5498                ALOGW("ResTable_typeSpec entry count inconsistent: given %d, previously %d",
5499                    (int)dtohl(typeSpec->entryCount), (int)t->entryCount);
5500                return (mError=BAD_TYPE);
5501            }
5502            t->typeSpecFlags = (const uint32_t*)(
5503                    ((const uint8_t*)typeSpec) + dtohs(typeSpec->header.headerSize));
5504            t->typeSpec = typeSpec;
5505
5506        } else if (ctype == RES_TABLE_TYPE_TYPE) {
5507            const ResTable_type* type = (const ResTable_type*)(chunk);
5508            err = validate_chunk(&type->header, sizeof(*type)-sizeof(ResTable_config)+4,
5509                                 endPos, "ResTable_type");
5510            if (err != NO_ERROR) {
5511                return (mError=err);
5512            }
5513
5514            const uint32_t typeSize = dtohl(type->header.size);
5515
5516            LOAD_TABLE_NOISY(printf("Type off %p: type=0x%x, headerSize=0x%x, size=%p\n",
5517                                    (void*)(base-(const uint8_t*)chunk),
5518                                    dtohs(type->header.type),
5519                                    dtohs(type->header.headerSize),
5520                                    (void*)typeSize));
5521            if (dtohs(type->header.headerSize)+(sizeof(uint32_t)*dtohl(type->entryCount))
5522                > typeSize) {
5523                ALOGW("ResTable_type entry index to %p extends beyond chunk end 0x%x.",
5524                     (void*)(dtohs(type->header.headerSize)
5525                             +(sizeof(uint32_t)*dtohl(type->entryCount))),
5526                     typeSize);
5527                return (mError=BAD_TYPE);
5528            }
5529            if (dtohl(type->entryCount) != 0
5530                && dtohl(type->entriesStart) > (typeSize-sizeof(ResTable_entry))) {
5531                ALOGW("ResTable_type entriesStart at 0x%x extends beyond chunk end 0x%x.",
5532                     dtohl(type->entriesStart), typeSize);
5533                return (mError=BAD_TYPE);
5534            }
5535            if (type->id == 0) {
5536                ALOGW("ResTable_type has an id of 0.");
5537                return (mError=BAD_TYPE);
5538            }
5539
5540            while (package->types.size() < type->id) {
5541                package->types.add(NULL);
5542            }
5543            Type* t = package->types[type->id-1];
5544            if (t == NULL) {
5545                t = new Type(header, package, dtohl(type->entryCount));
5546                package->types.editItemAt(type->id-1) = t;
5547            } else if (dtohl(type->entryCount) != t->entryCount) {
5548                ALOGW("ResTable_type entry count inconsistent: given %d, previously %d",
5549                    (int)dtohl(type->entryCount), (int)t->entryCount);
5550                return (mError=BAD_TYPE);
5551            }
5552
5553            TABLE_GETENTRY(
5554                ResTable_config thisConfig;
5555                thisConfig.copyFromDtoH(type->config);
5556                ALOGI("Adding config to type %d: %s\n",
5557                      type->id, thisConfig.toString().string()));
5558            t->configs.add(type);
5559        } else {
5560            status_t err = validate_chunk(chunk, sizeof(ResChunk_header),
5561                                          endPos, "ResTable_package:unknown");
5562            if (err != NO_ERROR) {
5563                return (mError=err);
5564            }
5565        }
5566        chunk = (const ResChunk_header*)
5567            (((const uint8_t*)chunk) + csize);
5568    }
5569
5570    if (group->typeCount == 0) {
5571        group->typeCount = package->types.size();
5572    }
5573
5574    return NO_ERROR;
5575}
5576
5577status_t ResTable::createIdmap(const ResTable& overlay,
5578        uint32_t targetCrc, uint32_t overlayCrc,
5579        const char* targetPath, const char* overlayPath,
5580        void** outData, size_t* outSize) const
5581{
5582    // see README for details on the format of map
5583    if (mPackageGroups.size() == 0) {
5584        ALOGW("idmap: target package has no package groups, cannot create idmap\n");
5585        return UNKNOWN_ERROR;
5586    }
5587    if (mPackageGroups[0]->packages.size() == 0) {
5588        ALOGW("idmap: target package has no packages in its first package group, "
5589                "cannot create idmap\n");
5590        return UNKNOWN_ERROR;
5591    }
5592
5593    Vector<Vector<uint32_t> > map;
5594    // overlaid packages are assumed to contain only one package group
5595    const PackageGroup* pg = mPackageGroups[0];
5596    const Package* pkg = pg->packages[0];
5597    size_t typeCount = pkg->types.size();
5598    // starting size is header + first item (number of types in map)
5599    *outSize = (IDMAP_HEADER_SIZE + 1) * sizeof(uint32_t);
5600    // overlay packages are assumed to contain only one package group
5601    const String16 overlayPackage(overlay.mPackageGroups[0]->packages[0]->package->name);
5602    const uint32_t pkg_id = pkg->package->id << 24;
5603
5604    for (size_t typeIndex = 0; typeIndex < typeCount; ++typeIndex) {
5605        ssize_t first = -1;
5606        ssize_t last = -1;
5607        const Type* typeConfigs = pkg->getType(typeIndex);
5608        ssize_t mapIndex = map.add();
5609        if (mapIndex < 0) {
5610            return NO_MEMORY;
5611        }
5612        Vector<uint32_t>& vector = map.editItemAt(mapIndex);
5613        for (size_t entryIndex = 0; entryIndex < typeConfigs->entryCount; ++entryIndex) {
5614            uint32_t resID = pkg_id
5615                | (0x00ff0000 & ((typeIndex+1)<<16))
5616                | (0x0000ffff & (entryIndex));
5617            resource_name resName;
5618            if (!this->getResourceName(resID, false, &resName)) {
5619                ALOGW("idmap: resource 0x%08x has spec but lacks values, skipping\n", resID);
5620                // add dummy value, or trimming leading/trailing zeroes later will fail
5621                vector.push(0);
5622                continue;
5623            }
5624
5625            const String16 overlayType(resName.type, resName.typeLen);
5626            const String16 overlayName(resName.name, resName.nameLen);
5627            uint32_t overlayResID = overlay.identifierForName(overlayName.string(),
5628                                                              overlayName.size(),
5629                                                              overlayType.string(),
5630                                                              overlayType.size(),
5631                                                              overlayPackage.string(),
5632                                                              overlayPackage.size());
5633            if (overlayResID != 0) {
5634                overlayResID = pkg_id | (0x00ffffff & overlayResID);
5635                last = Res_GETENTRY(resID);
5636                if (first == -1) {
5637                    first = Res_GETENTRY(resID);
5638                }
5639            }
5640            vector.push(overlayResID);
5641#if 0
5642            if (overlayResID != 0) {
5643                ALOGD("%s/%s 0x%08x -> 0x%08x\n",
5644                     String8(String16(resName.type)).string(),
5645                     String8(String16(resName.name)).string(),
5646                     resID, overlayResID);
5647            }
5648#endif
5649        }
5650
5651        if (first != -1) {
5652            // shave off trailing entries which lack overlay values
5653            const size_t last_past_one = last + 1;
5654            if (last_past_one < vector.size()) {
5655                vector.removeItemsAt(last_past_one, vector.size() - last_past_one);
5656            }
5657            // shave off leading entries which lack overlay values
5658            vector.removeItemsAt(0, first);
5659            // store offset to first overlaid resource ID of this type
5660            vector.insertAt((uint32_t)first, 0, 1);
5661            // reserve space for number and offset of entries, and the actual entries
5662            *outSize += (2 + vector.size()) * sizeof(uint32_t);
5663        } else {
5664            // no entries of current type defined in overlay package
5665            vector.clear();
5666            // reserve space for type offset
5667            *outSize += 1 * sizeof(uint32_t);
5668        }
5669    }
5670
5671    if ((*outData = malloc(*outSize)) == NULL) {
5672        return NO_MEMORY;
5673    }
5674    uint32_t* data = (uint32_t*)*outData;
5675    *data++ = htodl(IDMAP_MAGIC);
5676    *data++ = htodl(targetCrc);
5677    *data++ = htodl(overlayCrc);
5678    const char* paths[] = { targetPath, overlayPath };
5679    for (int j = 0; j < 2; ++j) {
5680        char* p = (char*)data;
5681        const char* path = paths[j];
5682        const size_t I = strlen(path);
5683        if (I > 255) {
5684            ALOGV("path exceeds expected 255 characters: %s\n", path);
5685            return UNKNOWN_ERROR;
5686        }
5687        for (size_t i = 0; i < 256; ++i) {
5688            *p++ = i < I ? path[i] : '\0';
5689        }
5690        data += 256 / sizeof(uint32_t);
5691    }
5692    const size_t mapSize = map.size();
5693    *data++ = htodl(mapSize);
5694    size_t offset = mapSize;
5695    for (size_t i = 0; i < mapSize; ++i) {
5696        const Vector<uint32_t>& vector = map.itemAt(i);
5697        const size_t N = vector.size();
5698        if (N == 0) {
5699            *data++ = htodl(0);
5700        } else {
5701            offset++;
5702            *data++ = htodl(offset);
5703            offset += N;
5704        }
5705    }
5706    if (offset == mapSize) {
5707        ALOGW("idmap: no resources in overlay package present in base package\n");
5708        return UNKNOWN_ERROR;
5709    }
5710    for (size_t i = 0; i < mapSize; ++i) {
5711        const Vector<uint32_t>& vector = map.itemAt(i);
5712        const size_t N = vector.size();
5713        if (N == 0) {
5714            continue;
5715        }
5716        if (N == 1) { // vector expected to hold (offset) + (N > 0 entries)
5717            ALOGW("idmap: type %d supposedly has entries, but no entries found\n", i);
5718            return UNKNOWN_ERROR;
5719        }
5720        *data++ = htodl(N - 1); // do not count the offset (which is vector's first element)
5721        for (size_t j = 0; j < N; ++j) {
5722            const uint32_t& overlayResID = vector.itemAt(j);
5723            *data++ = htodl(overlayResID);
5724        }
5725    }
5726
5727    return NO_ERROR;
5728}
5729
5730bool ResTable::getIdmapInfo(const void* idmap, size_t sizeBytes,
5731                            uint32_t* pTargetCrc, uint32_t* pOverlayCrc,
5732                            String8* pTargetPath, String8* pOverlayPath)
5733{
5734    const uint32_t* map = (const uint32_t*)idmap;
5735    if (!assertIdmapHeader(map, sizeBytes)) {
5736        return false;
5737    }
5738    if (pTargetCrc) {
5739        *pTargetCrc = map[1];
5740    }
5741    if (pOverlayCrc) {
5742        *pOverlayCrc = map[2];
5743    }
5744    if (pTargetPath) {
5745        pTargetPath->setTo(reinterpret_cast<const char*>(map + 3));
5746    }
5747    if (pOverlayPath) {
5748        pOverlayPath->setTo(reinterpret_cast<const char*>(map + 3 + 256 / sizeof(uint32_t)));
5749    }
5750    return true;
5751}
5752
5753
5754#define CHAR16_TO_CSTR(c16, len) (String8(String16(c16,len)).string())
5755
5756#define CHAR16_ARRAY_EQ(constant, var, len) \
5757        ((len == (sizeof(constant)/sizeof(constant[0]))) && (0 == memcmp((var), (constant), (len))))
5758
5759static void print_complex(uint32_t complex, bool isFraction)
5760{
5761    const float MANTISSA_MULT =
5762        1.0f / (1<<Res_value::COMPLEX_MANTISSA_SHIFT);
5763    const float RADIX_MULTS[] = {
5764        1.0f*MANTISSA_MULT, 1.0f/(1<<7)*MANTISSA_MULT,
5765        1.0f/(1<<15)*MANTISSA_MULT, 1.0f/(1<<23)*MANTISSA_MULT
5766    };
5767
5768    float value = (complex&(Res_value::COMPLEX_MANTISSA_MASK
5769                   <<Res_value::COMPLEX_MANTISSA_SHIFT))
5770            * RADIX_MULTS[(complex>>Res_value::COMPLEX_RADIX_SHIFT)
5771                            & Res_value::COMPLEX_RADIX_MASK];
5772    printf("%f", value);
5773
5774    if (!isFraction) {
5775        switch ((complex>>Res_value::COMPLEX_UNIT_SHIFT)&Res_value::COMPLEX_UNIT_MASK) {
5776            case Res_value::COMPLEX_UNIT_PX: printf("px"); break;
5777            case Res_value::COMPLEX_UNIT_DIP: printf("dp"); break;
5778            case Res_value::COMPLEX_UNIT_SP: printf("sp"); break;
5779            case Res_value::COMPLEX_UNIT_PT: printf("pt"); break;
5780            case Res_value::COMPLEX_UNIT_IN: printf("in"); break;
5781            case Res_value::COMPLEX_UNIT_MM: printf("mm"); break;
5782            default: printf(" (unknown unit)"); break;
5783        }
5784    } else {
5785        switch ((complex>>Res_value::COMPLEX_UNIT_SHIFT)&Res_value::COMPLEX_UNIT_MASK) {
5786            case Res_value::COMPLEX_UNIT_FRACTION: printf("%%"); break;
5787            case Res_value::COMPLEX_UNIT_FRACTION_PARENT: printf("%%p"); break;
5788            default: printf(" (unknown unit)"); break;
5789        }
5790    }
5791}
5792
5793// Normalize a string for output
5794String8 ResTable::normalizeForOutput( const char *input )
5795{
5796    String8 ret;
5797    char buff[2];
5798    buff[1] = '\0';
5799
5800    while (*input != '\0') {
5801        switch (*input) {
5802            // All interesting characters are in the ASCII zone, so we are making our own lives
5803            // easier by scanning the string one byte at a time.
5804        case '\\':
5805            ret += "\\\\";
5806            break;
5807        case '\n':
5808            ret += "\\n";
5809            break;
5810        case '"':
5811            ret += "\\\"";
5812            break;
5813        default:
5814            buff[0] = *input;
5815            ret += buff;
5816            break;
5817        }
5818
5819        input++;
5820    }
5821
5822    return ret;
5823}
5824
5825void ResTable::print_value(const Package* pkg, const Res_value& value) const
5826{
5827    if (value.dataType == Res_value::TYPE_NULL) {
5828        printf("(null)\n");
5829    } else if (value.dataType == Res_value::TYPE_REFERENCE) {
5830        printf("(reference) 0x%08x\n", value.data);
5831    } else if (value.dataType == Res_value::TYPE_ATTRIBUTE) {
5832        printf("(attribute) 0x%08x\n", value.data);
5833    } else if (value.dataType == Res_value::TYPE_STRING) {
5834        size_t len;
5835        const char* str8 = pkg->header->values.string8At(
5836                value.data, &len);
5837        if (str8 != NULL) {
5838            printf("(string8) \"%s\"\n", normalizeForOutput(str8).string());
5839        } else {
5840            const char16_t* str16 = pkg->header->values.stringAt(
5841                    value.data, &len);
5842            if (str16 != NULL) {
5843                printf("(string16) \"%s\"\n",
5844                    normalizeForOutput(String8(str16, len).string()).string());
5845            } else {
5846                printf("(string) null\n");
5847            }
5848        }
5849    } else if (value.dataType == Res_value::TYPE_FLOAT) {
5850        printf("(float) %g\n", *(const float*)&value.data);
5851    } else if (value.dataType == Res_value::TYPE_DIMENSION) {
5852        printf("(dimension) ");
5853        print_complex(value.data, false);
5854        printf("\n");
5855    } else if (value.dataType == Res_value::TYPE_FRACTION) {
5856        printf("(fraction) ");
5857        print_complex(value.data, true);
5858        printf("\n");
5859    } else if (value.dataType >= Res_value::TYPE_FIRST_COLOR_INT
5860            || value.dataType <= Res_value::TYPE_LAST_COLOR_INT) {
5861        printf("(color) #%08x\n", value.data);
5862    } else if (value.dataType == Res_value::TYPE_INT_BOOLEAN) {
5863        printf("(boolean) %s\n", value.data ? "true" : "false");
5864    } else if (value.dataType >= Res_value::TYPE_FIRST_INT
5865            || value.dataType <= Res_value::TYPE_LAST_INT) {
5866        printf("(int) 0x%08x or %d\n", value.data, value.data);
5867    } else {
5868        printf("(unknown type) t=0x%02x d=0x%08x (s=0x%04x r=0x%02x)\n",
5869               (int)value.dataType, (int)value.data,
5870               (int)value.size, (int)value.res0);
5871    }
5872}
5873
5874void ResTable::print(bool inclValues) const
5875{
5876    if (mError != 0) {
5877        printf("mError=0x%x (%s)\n", mError, strerror(mError));
5878    }
5879#if 0
5880    char localeStr[RESTABLE_MAX_LOCALE_LEN];
5881    mParams.getBcp47Locale(localeStr);
5882    printf("mParams=%s,\n" localeStr);
5883#endif
5884    size_t pgCount = mPackageGroups.size();
5885    printf("Package Groups (%d)\n", (int)pgCount);
5886    for (size_t pgIndex=0; pgIndex<pgCount; pgIndex++) {
5887        const PackageGroup* pg = mPackageGroups[pgIndex];
5888        printf("Package Group %d id=%d packageCount=%d name=%s\n",
5889                (int)pgIndex, pg->id, (int)pg->packages.size(),
5890                String8(pg->name).string());
5891
5892        size_t pkgCount = pg->packages.size();
5893        for (size_t pkgIndex=0; pkgIndex<pkgCount; pkgIndex++) {
5894            const Package* pkg = pg->packages[pkgIndex];
5895            size_t typeCount = pkg->types.size();
5896            printf("  Package %d id=%d name=%s typeCount=%d\n", (int)pkgIndex,
5897                    pkg->package->id, String8(String16(pkg->package->name)).string(),
5898                    (int)typeCount);
5899            for (size_t typeIndex=0; typeIndex<typeCount; typeIndex++) {
5900                const Type* typeConfigs = pkg->getType(typeIndex);
5901                if (typeConfigs == NULL) {
5902                    printf("    type %d NULL\n", (int)typeIndex);
5903                    continue;
5904                }
5905                const size_t NTC = typeConfigs->configs.size();
5906                printf("    type %d configCount=%d entryCount=%d\n",
5907                       (int)typeIndex, (int)NTC, (int)typeConfigs->entryCount);
5908                if (typeConfigs->typeSpecFlags != NULL) {
5909                    for (size_t entryIndex=0; entryIndex<typeConfigs->entryCount; entryIndex++) {
5910                        uint32_t resID = (0xff000000 & ((pkg->package->id)<<24))
5911                                    | (0x00ff0000 & ((typeIndex+1)<<16))
5912                                    | (0x0000ffff & (entryIndex));
5913                        resource_name resName;
5914                        if (this->getResourceName(resID, true, &resName)) {
5915                            String8 type8;
5916                            String8 name8;
5917                            if (resName.type8 != NULL) {
5918                                type8 = String8(resName.type8, resName.typeLen);
5919                            } else {
5920                                type8 = String8(resName.type, resName.typeLen);
5921                            }
5922                            if (resName.name8 != NULL) {
5923                                name8 = String8(resName.name8, resName.nameLen);
5924                            } else {
5925                                name8 = String8(resName.name, resName.nameLen);
5926                            }
5927                            printf("      spec resource 0x%08x %s:%s/%s: flags=0x%08x\n",
5928                                resID,
5929                                CHAR16_TO_CSTR(resName.package, resName.packageLen),
5930                                type8.string(), name8.string(),
5931                                dtohl(typeConfigs->typeSpecFlags[entryIndex]));
5932                        } else {
5933                            printf("      INVALID TYPE CONFIG FOR RESOURCE 0x%08x\n", resID);
5934                        }
5935                    }
5936                }
5937                for (size_t configIndex=0; configIndex<NTC; configIndex++) {
5938                    const ResTable_type* type = typeConfigs->configs[configIndex];
5939                    if ((((uint64_t)type)&0x3) != 0) {
5940                        printf("      NON-INTEGER ResTable_type ADDRESS: %p\n", type);
5941                        continue;
5942                    }
5943                    String8 configStr = type->config.toString();
5944                    printf("      config %s:\n", configStr.size() > 0
5945                            ? configStr.string() : "(default)");
5946                    size_t entryCount = dtohl(type->entryCount);
5947                    uint32_t entriesStart = dtohl(type->entriesStart);
5948                    if ((entriesStart&0x3) != 0) {
5949                        printf("      NON-INTEGER ResTable_type entriesStart OFFSET: 0x%x\n", entriesStart);
5950                        continue;
5951                    }
5952                    uint32_t typeSize = dtohl(type->header.size);
5953                    if ((typeSize&0x3) != 0) {
5954                        printf("      NON-INTEGER ResTable_type header.size: 0x%x\n", typeSize);
5955                        continue;
5956                    }
5957                    for (size_t entryIndex=0; entryIndex<entryCount; entryIndex++) {
5958
5959                        const uint8_t* const end = ((const uint8_t*)type)
5960                            + dtohl(type->header.size);
5961                        const uint32_t* const eindex = (const uint32_t*)
5962                            (((const uint8_t*)type) + dtohs(type->header.headerSize));
5963
5964                        uint32_t thisOffset = dtohl(eindex[entryIndex]);
5965                        if (thisOffset == ResTable_type::NO_ENTRY) {
5966                            continue;
5967                        }
5968
5969                        uint32_t resID = (0xff000000 & ((pkg->package->id)<<24))
5970                                    | (0x00ff0000 & ((typeIndex+1)<<16))
5971                                    | (0x0000ffff & (entryIndex));
5972                        resource_name resName;
5973                        if (this->getResourceName(resID, true, &resName)) {
5974                            String8 type8;
5975                            String8 name8;
5976                            if (resName.type8 != NULL) {
5977                                type8 = String8(resName.type8, resName.typeLen);
5978                            } else {
5979                                type8 = String8(resName.type, resName.typeLen);
5980                            }
5981                            if (resName.name8 != NULL) {
5982                                name8 = String8(resName.name8, resName.nameLen);
5983                            } else {
5984                                name8 = String8(resName.name, resName.nameLen);
5985                            }
5986                            printf("        resource 0x%08x %s:%s/%s: ", resID,
5987                                    CHAR16_TO_CSTR(resName.package, resName.packageLen),
5988                                    type8.string(), name8.string());
5989                        } else {
5990                            printf("        INVALID RESOURCE 0x%08x: ", resID);
5991                        }
5992                        if ((thisOffset&0x3) != 0) {
5993                            printf("NON-INTEGER OFFSET: 0x%x\n", thisOffset);
5994                            continue;
5995                        }
5996                        if ((thisOffset+sizeof(ResTable_entry)) > typeSize) {
5997                            printf("OFFSET OUT OF BOUNDS: 0x%x+0x%x (size is 0x%x)\n",
5998                                   entriesStart, thisOffset, typeSize);
5999                            continue;
6000                        }
6001
6002                        const ResTable_entry* ent = (const ResTable_entry*)
6003                            (((const uint8_t*)type) + entriesStart + thisOffset);
6004                        if (((entriesStart + thisOffset)&0x3) != 0) {
6005                            printf("NON-INTEGER ResTable_entry OFFSET: 0x%x\n",
6006                                 (entriesStart + thisOffset));
6007                            continue;
6008                        }
6009
6010                        uintptr_t esize = dtohs(ent->size);
6011                        if ((esize&0x3) != 0) {
6012                            printf("NON-INTEGER ResTable_entry SIZE: %p\n", (void *)esize);
6013                            continue;
6014                        }
6015                        if ((thisOffset+esize) > typeSize) {
6016                            printf("ResTable_entry OUT OF BOUNDS: 0x%x+0x%x+%p (size is 0x%x)\n",
6017                                   entriesStart, thisOffset, (void *)esize, typeSize);
6018                            continue;
6019                        }
6020
6021                        const Res_value* valuePtr = NULL;
6022                        const ResTable_map_entry* bagPtr = NULL;
6023                        Res_value value;
6024                        if ((dtohs(ent->flags)&ResTable_entry::FLAG_COMPLEX) != 0) {
6025                            printf("<bag>");
6026                            bagPtr = (const ResTable_map_entry*)ent;
6027                        } else {
6028                            valuePtr = (const Res_value*)
6029                                (((const uint8_t*)ent) + esize);
6030                            value.copyFrom_dtoh(*valuePtr);
6031                            printf("t=0x%02x d=0x%08x (s=0x%04x r=0x%02x)",
6032                                   (int)value.dataType, (int)value.data,
6033                                   (int)value.size, (int)value.res0);
6034                        }
6035
6036                        if ((dtohs(ent->flags)&ResTable_entry::FLAG_PUBLIC) != 0) {
6037                            printf(" (PUBLIC)");
6038                        }
6039                        printf("\n");
6040
6041                        if (inclValues) {
6042                            if (valuePtr != NULL) {
6043                                printf("          ");
6044                                print_value(pkg, value);
6045                            } else if (bagPtr != NULL) {
6046                                const int N = dtohl(bagPtr->count);
6047                                const uint8_t* baseMapPtr = (const uint8_t*)ent;
6048                                size_t mapOffset = esize;
6049                                const ResTable_map* mapPtr = (ResTable_map*)(baseMapPtr+mapOffset);
6050                                printf("          Parent=0x%08x, Count=%d\n",
6051                                    dtohl(bagPtr->parent.ident), N);
6052                                for (int i=0; i<N && mapOffset < (typeSize-sizeof(ResTable_map)); i++) {
6053                                    printf("          #%i (Key=0x%08x): ",
6054                                        i, dtohl(mapPtr->name.ident));
6055                                    value.copyFrom_dtoh(mapPtr->value);
6056                                    print_value(pkg, value);
6057                                    const size_t size = dtohs(mapPtr->value.size);
6058                                    mapOffset += size + sizeof(*mapPtr)-sizeof(mapPtr->value);
6059                                    mapPtr = (ResTable_map*)(baseMapPtr+mapOffset);
6060                                }
6061                            }
6062                        }
6063                    }
6064                }
6065            }
6066        }
6067    }
6068}
6069
6070}   // namespace android
6071