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 <utils/Atomic.h>
21#include <utils/ByteOrder.h>
22#include <utils/Debug.h>
23#include <utils/ResourceTypes.h>
24#include <utils/String16.h>
25#include <utils/String8.h>
26#include <utils/TextOutput.h>
27#include <utils/Log.h>
28
29#include <stdlib.h>
30#include <string.h>
31#include <memory.h>
32#include <ctype.h>
33#include <stdint.h>
34
35#ifndef INT32_MAX
36#define INT32_MAX ((int32_t)(2147483647))
37#endif
38
39#define POOL_NOISY(x) //x
40#define XML_NOISY(x) //x
41#define TABLE_NOISY(x) //x
42#define TABLE_GETENTRY(x) //x
43#define TABLE_SUPER_NOISY(x) //x
44#define LOAD_TABLE_NOISY(x) //x
45#define TABLE_THEME(x) //x
46
47namespace android {
48
49#ifdef HAVE_WINSOCK
50#undef  nhtol
51#undef  htonl
52
53#ifdef HAVE_LITTLE_ENDIAN
54#define ntohl(x)    ( ((x) << 24) | (((x) >> 24) & 255) | (((x) << 8) & 0xff0000) | (((x) >> 8) & 0xff00) )
55#define htonl(x)    ntohl(x)
56#define ntohs(x)    ( (((x) << 8) & 0xff00) | (((x) >> 8) & 255) )
57#define htons(x)    ntohs(x)
58#else
59#define ntohl(x)    (x)
60#define htonl(x)    (x)
61#define ntohs(x)    (x)
62#define htons(x)    (x)
63#endif
64#endif
65
66static void printToLogFunc(void* cookie, const char* txt)
67{
68    LOGV("%s", txt);
69}
70
71// Standard C isspace() is only required to look at the low byte of its input, so
72// produces incorrect results for UTF-16 characters.  For safety's sake, assume that
73// any high-byte UTF-16 code point is not whitespace.
74inline int isspace16(char16_t c) {
75    return (c < 0x0080 && isspace(c));
76}
77
78// range checked; guaranteed to NUL-terminate within the stated number of available slots
79// NOTE: if this truncates the dst string due to running out of space, no attempt is
80// made to avoid splitting surrogate pairs.
81static void strcpy16_dtoh(uint16_t* dst, const uint16_t* src, size_t avail)
82{
83    uint16_t* last = dst + avail - 1;
84    while (*src && (dst < last)) {
85        char16_t s = dtohs(*src);
86        *dst++ = s;
87        src++;
88    }
89    *dst = 0;
90}
91
92static status_t validate_chunk(const ResChunk_header* chunk,
93                               size_t minSize,
94                               const uint8_t* dataEnd,
95                               const char* name)
96{
97    const uint16_t headerSize = dtohs(chunk->headerSize);
98    const uint32_t size = dtohl(chunk->size);
99
100    if (headerSize >= minSize) {
101        if (headerSize <= size) {
102            if (((headerSize|size)&0x3) == 0) {
103                if ((ssize_t)size <= (dataEnd-((const uint8_t*)chunk))) {
104                    return NO_ERROR;
105                }
106                LOGW("%s data size %p extends beyond resource end %p.",
107                     name, (void*)size,
108                     (void*)(dataEnd-((const uint8_t*)chunk)));
109                return BAD_TYPE;
110            }
111            LOGW("%s size 0x%x or headerSize 0x%x is not on an integer boundary.",
112                 name, (int)size, (int)headerSize);
113            return BAD_TYPE;
114        }
115        LOGW("%s size %p is smaller than header size %p.",
116             name, (void*)size, (void*)(int)headerSize);
117        return BAD_TYPE;
118    }
119    LOGW("%s header size %p is too small.",
120         name, (void*)(int)headerSize);
121    return BAD_TYPE;
122}
123
124inline void Res_value::copyFrom_dtoh(const Res_value& src)
125{
126    size = dtohs(src.size);
127    res0 = src.res0;
128    dataType = src.dataType;
129    data = dtohl(src.data);
130}
131
132void Res_png_9patch::deviceToFile()
133{
134    for (int i = 0; i < numXDivs; i++) {
135        xDivs[i] = htonl(xDivs[i]);
136    }
137    for (int i = 0; i < numYDivs; i++) {
138        yDivs[i] = htonl(yDivs[i]);
139    }
140    paddingLeft = htonl(paddingLeft);
141    paddingRight = htonl(paddingRight);
142    paddingTop = htonl(paddingTop);
143    paddingBottom = htonl(paddingBottom);
144    for (int i=0; i<numColors; i++) {
145        colors[i] = htonl(colors[i]);
146    }
147}
148
149void Res_png_9patch::fileToDevice()
150{
151    for (int i = 0; i < numXDivs; i++) {
152        xDivs[i] = ntohl(xDivs[i]);
153    }
154    for (int i = 0; i < numYDivs; i++) {
155        yDivs[i] = ntohl(yDivs[i]);
156    }
157    paddingLeft = ntohl(paddingLeft);
158    paddingRight = ntohl(paddingRight);
159    paddingTop = ntohl(paddingTop);
160    paddingBottom = ntohl(paddingBottom);
161    for (int i=0; i<numColors; i++) {
162        colors[i] = ntohl(colors[i]);
163    }
164}
165
166size_t Res_png_9patch::serializedSize()
167{
168    // The size of this struct is 32 bytes on the 32-bit target system
169    // 4 * int8_t
170    // 4 * int32_t
171    // 3 * pointer
172    return 32
173            + numXDivs * sizeof(int32_t)
174            + numYDivs * sizeof(int32_t)
175            + numColors * sizeof(uint32_t);
176}
177
178void* Res_png_9patch::serialize()
179{
180    // Use calloc since we're going to leave a few holes in the data
181    // and want this to run cleanly under valgrind
182    void* newData = calloc(1, serializedSize());
183    serialize(newData);
184    return newData;
185}
186
187void Res_png_9patch::serialize(void * outData)
188{
189    char* data = (char*) outData;
190    memmove(data, &wasDeserialized, 4);     // copy  wasDeserialized, numXDivs, numYDivs, numColors
191    memmove(data + 12, &paddingLeft, 16);   // copy paddingXXXX
192    data += 32;
193
194    memmove(data, this->xDivs, numXDivs * sizeof(int32_t));
195    data +=  numXDivs * sizeof(int32_t);
196    memmove(data, this->yDivs, numYDivs * sizeof(int32_t));
197    data +=  numYDivs * sizeof(int32_t);
198    memmove(data, this->colors, numColors * sizeof(uint32_t));
199}
200
201static void deserializeInternal(const void* inData, Res_png_9patch* outData) {
202    char* patch = (char*) inData;
203    if (inData != outData) {
204        memmove(&outData->wasDeserialized, patch, 4);     // copy  wasDeserialized, numXDivs, numYDivs, numColors
205        memmove(&outData->paddingLeft, patch + 12, 4);     // copy  wasDeserialized, numXDivs, numYDivs, numColors
206    }
207    outData->wasDeserialized = true;
208    char* data = (char*)outData;
209    data +=  sizeof(Res_png_9patch);
210    outData->xDivs = (int32_t*) data;
211    data +=  outData->numXDivs * sizeof(int32_t);
212    outData->yDivs = (int32_t*) data;
213    data +=  outData->numYDivs * sizeof(int32_t);
214    outData->colors = (uint32_t*) data;
215}
216
217Res_png_9patch* Res_png_9patch::deserialize(const void* inData)
218{
219    if (sizeof(void*) != sizeof(int32_t)) {
220        LOGE("Cannot deserialize on non 32-bit system\n");
221        return NULL;
222    }
223    deserializeInternal(inData, (Res_png_9patch*) inData);
224    return (Res_png_9patch*) inData;
225}
226
227// --------------------------------------------------------------------
228// --------------------------------------------------------------------
229// --------------------------------------------------------------------
230
231ResStringPool::ResStringPool()
232    : mError(NO_INIT), mOwnedData(NULL)
233{
234}
235
236ResStringPool::ResStringPool(const void* data, size_t size, bool copyData)
237    : mError(NO_INIT), mOwnedData(NULL)
238{
239    setTo(data, size, copyData);
240}
241
242ResStringPool::~ResStringPool()
243{
244    uninit();
245}
246
247status_t ResStringPool::setTo(const void* data, size_t size, bool copyData)
248{
249    if (!data || !size) {
250        return (mError=BAD_TYPE);
251    }
252
253    uninit();
254
255    const bool notDeviceEndian = htods(0xf0) != 0xf0;
256
257    if (copyData || notDeviceEndian) {
258        mOwnedData = malloc(size);
259        if (mOwnedData == NULL) {
260            return (mError=NO_MEMORY);
261        }
262        memcpy(mOwnedData, data, size);
263        data = mOwnedData;
264    }
265
266    mHeader = (const ResStringPool_header*)data;
267
268    if (notDeviceEndian) {
269        ResStringPool_header* h = const_cast<ResStringPool_header*>(mHeader);
270        h->header.headerSize = dtohs(mHeader->header.headerSize);
271        h->header.type = dtohs(mHeader->header.type);
272        h->header.size = dtohl(mHeader->header.size);
273        h->stringCount = dtohl(mHeader->stringCount);
274        h->styleCount = dtohl(mHeader->styleCount);
275        h->flags = dtohl(mHeader->flags);
276        h->stringsStart = dtohl(mHeader->stringsStart);
277        h->stylesStart = dtohl(mHeader->stylesStart);
278    }
279
280    if (mHeader->header.headerSize > mHeader->header.size
281            || mHeader->header.size > size) {
282        LOGW("Bad string block: header size %d or total size %d is larger than data size %d\n",
283                (int)mHeader->header.headerSize, (int)mHeader->header.size, (int)size);
284        return (mError=BAD_TYPE);
285    }
286    mSize = mHeader->header.size;
287    mEntries = (const uint32_t*)
288        (((const uint8_t*)data)+mHeader->header.headerSize);
289
290    if (mHeader->stringCount > 0) {
291        if ((mHeader->stringCount*sizeof(uint32_t) < mHeader->stringCount)  // uint32 overflow?
292            || (mHeader->header.headerSize+(mHeader->stringCount*sizeof(uint32_t)))
293                > size) {
294            LOGW("Bad string block: entry of %d items extends past data size %d\n",
295                    (int)(mHeader->header.headerSize+(mHeader->stringCount*sizeof(uint32_t))),
296                    (int)size);
297            return (mError=BAD_TYPE);
298        }
299        mStrings = (const char16_t*)
300            (((const uint8_t*)data)+mHeader->stringsStart);
301        if (mHeader->stringsStart >= (mHeader->header.size-sizeof(uint16_t))) {
302            LOGW("Bad string block: string pool starts at %d, after total size %d\n",
303                    (int)mHeader->stringsStart, (int)mHeader->header.size);
304            return (mError=BAD_TYPE);
305        }
306        if (mHeader->styleCount == 0) {
307            mStringPoolSize =
308                (mHeader->header.size-mHeader->stringsStart)/sizeof(uint16_t);
309        } else {
310            // check invariant: styles follow the strings
311            if (mHeader->stylesStart <= mHeader->stringsStart) {
312                LOGW("Bad style block: style block starts at %d, before strings at %d\n",
313                    (int)mHeader->stylesStart, (int)mHeader->stringsStart);
314                return (mError=BAD_TYPE);
315            }
316            mStringPoolSize =
317                (mHeader->stylesStart-mHeader->stringsStart)/sizeof(uint16_t);
318        }
319
320        // check invariant: stringCount > 0 requires a string pool to exist
321        if (mStringPoolSize == 0) {
322            LOGW("Bad string block: stringCount is %d but pool size is 0\n", (int)mHeader->stringCount);
323            return (mError=BAD_TYPE);
324        }
325
326        if (notDeviceEndian) {
327            size_t i;
328            uint32_t* e = const_cast<uint32_t*>(mEntries);
329            for (i=0; i<mHeader->stringCount; i++) {
330                e[i] = dtohl(mEntries[i]);
331            }
332            char16_t* s = const_cast<char16_t*>(mStrings);
333            for (i=0; i<mStringPoolSize; i++) {
334                s[i] = dtohs(mStrings[i]);
335            }
336        }
337
338        if (mStrings[mStringPoolSize-1] != 0) {
339            LOGW("Bad string block: last string is not 0-terminated\n");
340            return (mError=BAD_TYPE);
341        }
342    } else {
343        mStrings = NULL;
344        mStringPoolSize = 0;
345    }
346
347    if (mHeader->styleCount > 0) {
348        mEntryStyles = mEntries + mHeader->stringCount;
349        // invariant: integer overflow in calculating mEntryStyles
350        if (mEntryStyles < mEntries) {
351            LOGW("Bad string block: integer overflow finding styles\n");
352            return (mError=BAD_TYPE);
353        }
354
355        if (((const uint8_t*)mEntryStyles-(const uint8_t*)mHeader) > (int)size) {
356            LOGW("Bad string block: entry of %d styles extends past data size %d\n",
357                    (int)((const uint8_t*)mEntryStyles-(const uint8_t*)mHeader),
358                    (int)size);
359            return (mError=BAD_TYPE);
360        }
361        mStyles = (const uint32_t*)
362            (((const uint8_t*)data)+mHeader->stylesStart);
363        if (mHeader->stylesStart >= mHeader->header.size) {
364            LOGW("Bad string block: style pool starts %d, after total size %d\n",
365                    (int)mHeader->stylesStart, (int)mHeader->header.size);
366            return (mError=BAD_TYPE);
367        }
368        mStylePoolSize =
369            (mHeader->header.size-mHeader->stylesStart)/sizeof(uint32_t);
370
371        if (notDeviceEndian) {
372            size_t i;
373            uint32_t* e = const_cast<uint32_t*>(mEntryStyles);
374            for (i=0; i<mHeader->styleCount; i++) {
375                e[i] = dtohl(mEntryStyles[i]);
376            }
377            uint32_t* s = const_cast<uint32_t*>(mStyles);
378            for (i=0; i<mStylePoolSize; i++) {
379                s[i] = dtohl(mStyles[i]);
380            }
381        }
382
383        const ResStringPool_span endSpan = {
384            { htodl(ResStringPool_span::END) },
385            htodl(ResStringPool_span::END), htodl(ResStringPool_span::END)
386        };
387        if (memcmp(&mStyles[mStylePoolSize-(sizeof(endSpan)/sizeof(uint32_t))],
388                   &endSpan, sizeof(endSpan)) != 0) {
389            LOGW("Bad string block: last style is not 0xFFFFFFFF-terminated\n");
390            return (mError=BAD_TYPE);
391        }
392    } else {
393        mEntryStyles = NULL;
394        mStyles = NULL;
395        mStylePoolSize = 0;
396    }
397
398    return (mError=NO_ERROR);
399}
400
401status_t ResStringPool::getError() const
402{
403    return mError;
404}
405
406void ResStringPool::uninit()
407{
408    mError = NO_INIT;
409    if (mOwnedData) {
410        free(mOwnedData);
411        mOwnedData = NULL;
412    }
413}
414
415const uint16_t* ResStringPool::stringAt(size_t idx, size_t* outLen) const
416{
417    if (mError == NO_ERROR && idx < mHeader->stringCount) {
418        const uint32_t off = (mEntries[idx]/sizeof(uint16_t));
419        if (off < (mStringPoolSize-1)) {
420            const char16_t* str = mStrings+off;
421            *outLen = *str;
422            if ((*str)&0x8000) {
423                str++;
424                *outLen = (((*outLen)&0x7fff)<<16) + *str;
425            }
426            if ((uint32_t)(str+1+*outLen-mStrings) < mStringPoolSize) {
427                return str+1;
428            } else {
429                LOGW("Bad string block: string #%d extends to %d, past end at %d\n",
430                        (int)idx, (int)(str+1+*outLen-mStrings), (int)mStringPoolSize);
431            }
432        } else {
433            LOGW("Bad string block: string #%d entry is at %d, past end at %d\n",
434                    (int)idx, (int)(off*sizeof(uint16_t)),
435                    (int)(mStringPoolSize*sizeof(uint16_t)));
436        }
437    }
438    return NULL;
439}
440
441const ResStringPool_span* ResStringPool::styleAt(const ResStringPool_ref& ref) const
442{
443    return styleAt(ref.index);
444}
445
446const ResStringPool_span* ResStringPool::styleAt(size_t idx) const
447{
448    if (mError == NO_ERROR && idx < mHeader->styleCount) {
449        const uint32_t off = (mEntryStyles[idx]/sizeof(uint32_t));
450        if (off < mStylePoolSize) {
451            return (const ResStringPool_span*)(mStyles+off);
452        } else {
453            LOGW("Bad string block: style #%d entry is at %d, past end at %d\n",
454                    (int)idx, (int)(off*sizeof(uint32_t)),
455                    (int)(mStylePoolSize*sizeof(uint32_t)));
456        }
457    }
458    return NULL;
459}
460
461ssize_t ResStringPool::indexOfString(const char16_t* str, size_t strLen) const
462{
463    if (mError != NO_ERROR) {
464        return mError;
465    }
466
467    size_t len;
468
469    if (mHeader->flags&ResStringPool_header::SORTED_FLAG) {
470        // Do a binary search for the string...
471        ssize_t l = 0;
472        ssize_t h = mHeader->stringCount-1;
473
474        ssize_t mid;
475        while (l <= h) {
476            mid = l + (h - l)/2;
477            const char16_t* s = stringAt(mid, &len);
478            int c = s ? strzcmp16(s, len, str, strLen) : -1;
479            POOL_NOISY(printf("Looking for %s, at %s, cmp=%d, l/mid/h=%d/%d/%d\n",
480                         String8(str).string(),
481                         String8(s).string(),
482                         c, (int)l, (int)mid, (int)h));
483            if (c == 0) {
484                return mid;
485            } else if (c < 0) {
486                l = mid + 1;
487            } else {
488                h = mid - 1;
489            }
490        }
491    } else {
492        // It is unusual to get the ID from an unsorted string block...
493        // most often this happens because we want to get IDs for style
494        // span tags; since those always appear at the end of the string
495        // block, start searching at the back.
496        for (int i=mHeader->stringCount-1; i>=0; i--) {
497            const char16_t* s = stringAt(i, &len);
498            POOL_NOISY(printf("Looking for %s, at %s, i=%d\n",
499                         String8(str, strLen).string(),
500                         String8(s).string(),
501                         i));
502            if (s && strzcmp16(s, len, str, strLen) == 0) {
503                return i;
504            }
505        }
506    }
507
508    return NAME_NOT_FOUND;
509}
510
511size_t ResStringPool::size() const
512{
513    return (mError == NO_ERROR) ? mHeader->stringCount : 0;
514}
515
516// --------------------------------------------------------------------
517// --------------------------------------------------------------------
518// --------------------------------------------------------------------
519
520ResXMLParser::ResXMLParser(const ResXMLTree& tree)
521    : mTree(tree), mEventCode(BAD_DOCUMENT)
522{
523}
524
525void ResXMLParser::restart()
526{
527    mCurNode = NULL;
528    mEventCode = mTree.mError == NO_ERROR ? START_DOCUMENT : BAD_DOCUMENT;
529}
530
531ResXMLParser::event_code_t ResXMLParser::getEventType() const
532{
533    return mEventCode;
534}
535
536ResXMLParser::event_code_t ResXMLParser::next()
537{
538    if (mEventCode == START_DOCUMENT) {
539        mCurNode = mTree.mRootNode;
540        mCurExt = mTree.mRootExt;
541        return (mEventCode=mTree.mRootCode);
542    } else if (mEventCode >= FIRST_CHUNK_CODE) {
543        return nextNode();
544    }
545    return mEventCode;
546}
547
548int32_t ResXMLParser::getCommentID() const
549{
550    return mCurNode != NULL ? dtohl(mCurNode->comment.index) : -1;
551}
552
553const uint16_t* ResXMLParser::getComment(size_t* outLen) const
554{
555    int32_t id = getCommentID();
556    return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
557}
558
559uint32_t ResXMLParser::getLineNumber() const
560{
561    return mCurNode != NULL ? dtohl(mCurNode->lineNumber) : -1;
562}
563
564int32_t ResXMLParser::getTextID() const
565{
566    if (mEventCode == TEXT) {
567        return dtohl(((const ResXMLTree_cdataExt*)mCurExt)->data.index);
568    }
569    return -1;
570}
571
572const uint16_t* ResXMLParser::getText(size_t* outLen) const
573{
574    int32_t id = getTextID();
575    return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
576}
577
578ssize_t ResXMLParser::getTextValue(Res_value* outValue) const
579{
580    if (mEventCode == TEXT) {
581        outValue->copyFrom_dtoh(((const ResXMLTree_cdataExt*)mCurExt)->typedData);
582        return sizeof(Res_value);
583    }
584    return BAD_TYPE;
585}
586
587int32_t ResXMLParser::getNamespacePrefixID() const
588{
589    if (mEventCode == START_NAMESPACE || mEventCode == END_NAMESPACE) {
590        return dtohl(((const ResXMLTree_namespaceExt*)mCurExt)->prefix.index);
591    }
592    return -1;
593}
594
595const uint16_t* ResXMLParser::getNamespacePrefix(size_t* outLen) const
596{
597    int32_t id = getNamespacePrefixID();
598    //printf("prefix=%d  event=%p\n", id, mEventCode);
599    return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
600}
601
602int32_t ResXMLParser::getNamespaceUriID() const
603{
604    if (mEventCode == START_NAMESPACE || mEventCode == END_NAMESPACE) {
605        return dtohl(((const ResXMLTree_namespaceExt*)mCurExt)->uri.index);
606    }
607    return -1;
608}
609
610const uint16_t* ResXMLParser::getNamespaceUri(size_t* outLen) const
611{
612    int32_t id = getNamespaceUriID();
613    //printf("uri=%d  event=%p\n", id, mEventCode);
614    return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
615}
616
617int32_t ResXMLParser::getElementNamespaceID() const
618{
619    if (mEventCode == START_TAG) {
620        return dtohl(((const ResXMLTree_attrExt*)mCurExt)->ns.index);
621    }
622    if (mEventCode == END_TAG) {
623        return dtohl(((const ResXMLTree_endElementExt*)mCurExt)->ns.index);
624    }
625    return -1;
626}
627
628const uint16_t* ResXMLParser::getElementNamespace(size_t* outLen) const
629{
630    int32_t id = getElementNamespaceID();
631    return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
632}
633
634int32_t ResXMLParser::getElementNameID() const
635{
636    if (mEventCode == START_TAG) {
637        return dtohl(((const ResXMLTree_attrExt*)mCurExt)->name.index);
638    }
639    if (mEventCode == END_TAG) {
640        return dtohl(((const ResXMLTree_endElementExt*)mCurExt)->name.index);
641    }
642    return -1;
643}
644
645const uint16_t* ResXMLParser::getElementName(size_t* outLen) const
646{
647    int32_t id = getElementNameID();
648    return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
649}
650
651size_t ResXMLParser::getAttributeCount() const
652{
653    if (mEventCode == START_TAG) {
654        return dtohs(((const ResXMLTree_attrExt*)mCurExt)->attributeCount);
655    }
656    return 0;
657}
658
659int32_t ResXMLParser::getAttributeNamespaceID(size_t idx) const
660{
661    if (mEventCode == START_TAG) {
662        const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt;
663        if (idx < dtohs(tag->attributeCount)) {
664            const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*)
665                (((const uint8_t*)tag)
666                 + dtohs(tag->attributeStart)
667                 + (dtohs(tag->attributeSize)*idx));
668            return dtohl(attr->ns.index);
669        }
670    }
671    return -2;
672}
673
674const uint16_t* ResXMLParser::getAttributeNamespace(size_t idx, size_t* outLen) const
675{
676    int32_t id = getAttributeNamespaceID(idx);
677    //printf("attribute namespace=%d  idx=%d  event=%p\n", id, idx, mEventCode);
678    //XML_NOISY(printf("getAttributeNamespace 0x%x=0x%x\n", idx, id));
679    return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
680}
681
682int32_t ResXMLParser::getAttributeNameID(size_t idx) const
683{
684    if (mEventCode == START_TAG) {
685        const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt;
686        if (idx < dtohs(tag->attributeCount)) {
687            const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*)
688                (((const uint8_t*)tag)
689                 + dtohs(tag->attributeStart)
690                 + (dtohs(tag->attributeSize)*idx));
691            return dtohl(attr->name.index);
692        }
693    }
694    return -1;
695}
696
697const uint16_t* ResXMLParser::getAttributeName(size_t idx, size_t* outLen) const
698{
699    int32_t id = getAttributeNameID(idx);
700    //printf("attribute name=%d  idx=%d  event=%p\n", id, idx, mEventCode);
701    //XML_NOISY(printf("getAttributeName 0x%x=0x%x\n", idx, id));
702    return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
703}
704
705uint32_t ResXMLParser::getAttributeNameResID(size_t idx) const
706{
707    int32_t id = getAttributeNameID(idx);
708    if (id >= 0 && (size_t)id < mTree.mNumResIds) {
709        return dtohl(mTree.mResIds[id]);
710    }
711    return 0;
712}
713
714int32_t ResXMLParser::getAttributeValueStringID(size_t idx) const
715{
716    if (mEventCode == START_TAG) {
717        const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt;
718        if (idx < dtohs(tag->attributeCount)) {
719            const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*)
720                (((const uint8_t*)tag)
721                 + dtohs(tag->attributeStart)
722                 + (dtohs(tag->attributeSize)*idx));
723            return dtohl(attr->rawValue.index);
724        }
725    }
726    return -1;
727}
728
729const uint16_t* ResXMLParser::getAttributeStringValue(size_t idx, size_t* outLen) const
730{
731    int32_t id = getAttributeValueStringID(idx);
732    //XML_NOISY(printf("getAttributeValue 0x%x=0x%x\n", idx, id));
733    return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
734}
735
736int32_t ResXMLParser::getAttributeDataType(size_t idx) const
737{
738    if (mEventCode == START_TAG) {
739        const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt;
740        if (idx < dtohs(tag->attributeCount)) {
741            const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*)
742                (((const uint8_t*)tag)
743                 + dtohs(tag->attributeStart)
744                 + (dtohs(tag->attributeSize)*idx));
745            return attr->typedValue.dataType;
746        }
747    }
748    return Res_value::TYPE_NULL;
749}
750
751int32_t ResXMLParser::getAttributeData(size_t idx) const
752{
753    if (mEventCode == START_TAG) {
754        const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt;
755        if (idx < dtohs(tag->attributeCount)) {
756            const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*)
757                (((const uint8_t*)tag)
758                 + dtohs(tag->attributeStart)
759                 + (dtohs(tag->attributeSize)*idx));
760            return dtohl(attr->typedValue.data);
761        }
762    }
763    return 0;
764}
765
766ssize_t ResXMLParser::getAttributeValue(size_t idx, Res_value* outValue) const
767{
768    if (mEventCode == START_TAG) {
769        const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt;
770        if (idx < dtohs(tag->attributeCount)) {
771            const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*)
772                (((const uint8_t*)tag)
773                 + dtohs(tag->attributeStart)
774                 + (dtohs(tag->attributeSize)*idx));
775            outValue->copyFrom_dtoh(attr->typedValue);
776            return sizeof(Res_value);
777        }
778    }
779    return BAD_TYPE;
780}
781
782ssize_t ResXMLParser::indexOfAttribute(const char* ns, const char* attr) const
783{
784    String16 nsStr(ns != NULL ? ns : "");
785    String16 attrStr(attr);
786    return indexOfAttribute(ns ? nsStr.string() : NULL, ns ? nsStr.size() : 0,
787                            attrStr.string(), attrStr.size());
788}
789
790ssize_t ResXMLParser::indexOfAttribute(const char16_t* ns, size_t nsLen,
791                                       const char16_t* attr, size_t attrLen) const
792{
793    if (mEventCode == START_TAG) {
794        const size_t N = getAttributeCount();
795        for (size_t i=0; i<N; i++) {
796            size_t curNsLen, curAttrLen;
797            const char16_t* curNs = getAttributeNamespace(i, &curNsLen);
798            const char16_t* curAttr = getAttributeName(i, &curAttrLen);
799            //printf("%d: ns=%p attr=%p curNs=%p curAttr=%p\n",
800            //       i, ns, attr, curNs, curAttr);
801            //printf(" --> attr=%s, curAttr=%s\n",
802            //       String8(attr).string(), String8(curAttr).string());
803            if (attr && curAttr && (strzcmp16(attr, attrLen, curAttr, curAttrLen) == 0)) {
804                if (ns == NULL) {
805                    if (curNs == NULL) return i;
806                } else if (curNs != NULL) {
807                    //printf(" --> ns=%s, curNs=%s\n",
808                    //       String8(ns).string(), String8(curNs).string());
809                    if (strzcmp16(ns, nsLen, curNs, curNsLen) == 0) return i;
810                }
811            }
812        }
813    }
814
815    return NAME_NOT_FOUND;
816}
817
818ssize_t ResXMLParser::indexOfID() const
819{
820    if (mEventCode == START_TAG) {
821        const ssize_t idx = dtohs(((const ResXMLTree_attrExt*)mCurExt)->idIndex);
822        if (idx > 0) return (idx-1);
823    }
824    return NAME_NOT_FOUND;
825}
826
827ssize_t ResXMLParser::indexOfClass() const
828{
829    if (mEventCode == START_TAG) {
830        const ssize_t idx = dtohs(((const ResXMLTree_attrExt*)mCurExt)->classIndex);
831        if (idx > 0) return (idx-1);
832    }
833    return NAME_NOT_FOUND;
834}
835
836ssize_t ResXMLParser::indexOfStyle() const
837{
838    if (mEventCode == START_TAG) {
839        const ssize_t idx = dtohs(((const ResXMLTree_attrExt*)mCurExt)->styleIndex);
840        if (idx > 0) return (idx-1);
841    }
842    return NAME_NOT_FOUND;
843}
844
845ResXMLParser::event_code_t ResXMLParser::nextNode()
846{
847    if (mEventCode < 0) {
848        return mEventCode;
849    }
850
851    do {
852        const ResXMLTree_node* next = (const ResXMLTree_node*)
853            (((const uint8_t*)mCurNode) + dtohl(mCurNode->header.size));
854        //LOGW("Next node: prev=%p, next=%p\n", mCurNode, next);
855
856        if (((const uint8_t*)next) >= mTree.mDataEnd) {
857            mCurNode = NULL;
858            return (mEventCode=END_DOCUMENT);
859        }
860
861        if (mTree.validateNode(next) != NO_ERROR) {
862            mCurNode = NULL;
863            return (mEventCode=BAD_DOCUMENT);
864        }
865
866        mCurNode = next;
867        const uint16_t headerSize = dtohs(next->header.headerSize);
868        const uint32_t totalSize = dtohl(next->header.size);
869        mCurExt = ((const uint8_t*)next) + headerSize;
870        size_t minExtSize = 0;
871        event_code_t eventCode = (event_code_t)dtohs(next->header.type);
872        switch ((mEventCode=eventCode)) {
873            case RES_XML_START_NAMESPACE_TYPE:
874            case RES_XML_END_NAMESPACE_TYPE:
875                minExtSize = sizeof(ResXMLTree_namespaceExt);
876                break;
877            case RES_XML_START_ELEMENT_TYPE:
878                minExtSize = sizeof(ResXMLTree_attrExt);
879                break;
880            case RES_XML_END_ELEMENT_TYPE:
881                minExtSize = sizeof(ResXMLTree_endElementExt);
882                break;
883            case RES_XML_CDATA_TYPE:
884                minExtSize = sizeof(ResXMLTree_cdataExt);
885                break;
886            default:
887                LOGW("Unknown XML block: header type %d in node at %d\n",
888                     (int)dtohs(next->header.type),
889                     (int)(((const uint8_t*)next)-((const uint8_t*)mTree.mHeader)));
890                continue;
891        }
892
893        if ((totalSize-headerSize) < minExtSize) {
894            LOGW("Bad XML block: header type 0x%x in node at 0x%x has size %d, need %d\n",
895                 (int)dtohs(next->header.type),
896                 (int)(((const uint8_t*)next)-((const uint8_t*)mTree.mHeader)),
897                 (int)(totalSize-headerSize), (int)minExtSize);
898            return (mEventCode=BAD_DOCUMENT);
899        }
900
901        //printf("CurNode=%p, CurExt=%p, headerSize=%d, minExtSize=%d\n",
902        //       mCurNode, mCurExt, headerSize, minExtSize);
903
904        return eventCode;
905    } while (true);
906}
907
908void ResXMLParser::getPosition(ResXMLParser::ResXMLPosition* pos) const
909{
910    pos->eventCode = mEventCode;
911    pos->curNode = mCurNode;
912    pos->curExt = mCurExt;
913}
914
915void ResXMLParser::setPosition(const ResXMLParser::ResXMLPosition& pos)
916{
917    mEventCode = pos.eventCode;
918    mCurNode = pos.curNode;
919    mCurExt = pos.curExt;
920}
921
922
923// --------------------------------------------------------------------
924
925static volatile int32_t gCount = 0;
926
927ResXMLTree::ResXMLTree()
928    : ResXMLParser(*this)
929    , mError(NO_INIT), mOwnedData(NULL)
930{
931    //LOGI("Creating ResXMLTree %p #%d\n", this, android_atomic_inc(&gCount)+1);
932    restart();
933}
934
935ResXMLTree::ResXMLTree(const void* data, size_t size, bool copyData)
936    : ResXMLParser(*this)
937    , mError(NO_INIT), mOwnedData(NULL)
938{
939    //LOGI("Creating ResXMLTree %p #%d\n", this, android_atomic_inc(&gCount)+1);
940    setTo(data, size, copyData);
941}
942
943ResXMLTree::~ResXMLTree()
944{
945    //LOGI("Destroying ResXMLTree in %p #%d\n", this, android_atomic_dec(&gCount)-1);
946    uninit();
947}
948
949status_t ResXMLTree::setTo(const void* data, size_t size, bool copyData)
950{
951    uninit();
952    mEventCode = START_DOCUMENT;
953
954    if (copyData) {
955        mOwnedData = malloc(size);
956        if (mOwnedData == NULL) {
957            return (mError=NO_MEMORY);
958        }
959        memcpy(mOwnedData, data, size);
960        data = mOwnedData;
961    }
962
963    mHeader = (const ResXMLTree_header*)data;
964    mSize = dtohl(mHeader->header.size);
965    if (dtohs(mHeader->header.headerSize) > mSize || mSize > size) {
966        LOGW("Bad XML block: header size %d or total size %d is larger than data size %d\n",
967             (int)dtohs(mHeader->header.headerSize),
968             (int)dtohl(mHeader->header.size), (int)size);
969        mError = BAD_TYPE;
970        restart();
971        return mError;
972    }
973    mDataEnd = ((const uint8_t*)mHeader) + mSize;
974
975    mStrings.uninit();
976    mRootNode = NULL;
977    mResIds = NULL;
978    mNumResIds = 0;
979
980    // First look for a couple interesting chunks: the string block
981    // and first XML node.
982    const ResChunk_header* chunk =
983        (const ResChunk_header*)(((const uint8_t*)mHeader) + dtohs(mHeader->header.headerSize));
984    const ResChunk_header* lastChunk = chunk;
985    while (((const uint8_t*)chunk) < (mDataEnd-sizeof(ResChunk_header)) &&
986           ((const uint8_t*)chunk) < (mDataEnd-dtohl(chunk->size))) {
987        status_t err = validate_chunk(chunk, sizeof(ResChunk_header), mDataEnd, "XML");
988        if (err != NO_ERROR) {
989            mError = err;
990            goto done;
991        }
992        const uint16_t type = dtohs(chunk->type);
993        const size_t size = dtohl(chunk->size);
994        XML_NOISY(printf("Scanning @ %p: type=0x%x, size=0x%x\n",
995                     (void*)(((uint32_t)chunk)-((uint32_t)mHeader)), type, size));
996        if (type == RES_STRING_POOL_TYPE) {
997            mStrings.setTo(chunk, size);
998        } else if (type == RES_XML_RESOURCE_MAP_TYPE) {
999            mResIds = (const uint32_t*)
1000                (((const uint8_t*)chunk)+dtohs(chunk->headerSize));
1001            mNumResIds = (dtohl(chunk->size)-dtohs(chunk->headerSize))/sizeof(uint32_t);
1002        } else if (type >= RES_XML_FIRST_CHUNK_TYPE
1003                   && type <= RES_XML_LAST_CHUNK_TYPE) {
1004            if (validateNode((const ResXMLTree_node*)chunk) != NO_ERROR) {
1005                mError = BAD_TYPE;
1006                goto done;
1007            }
1008            mCurNode = (const ResXMLTree_node*)lastChunk;
1009            if (nextNode() == BAD_DOCUMENT) {
1010                mError = BAD_TYPE;
1011                goto done;
1012            }
1013            mRootNode = mCurNode;
1014            mRootExt = mCurExt;
1015            mRootCode = mEventCode;
1016            break;
1017        } else {
1018            XML_NOISY(printf("Skipping unknown chunk!\n"));
1019        }
1020        lastChunk = chunk;
1021        chunk = (const ResChunk_header*)
1022            (((const uint8_t*)chunk) + size);
1023    }
1024
1025    if (mRootNode == NULL) {
1026        LOGW("Bad XML block: no root element node found\n");
1027        mError = BAD_TYPE;
1028        goto done;
1029    }
1030
1031    mError = mStrings.getError();
1032
1033done:
1034    restart();
1035    return mError;
1036}
1037
1038status_t ResXMLTree::getError() const
1039{
1040    return mError;
1041}
1042
1043void ResXMLTree::uninit()
1044{
1045    mError = NO_INIT;
1046    if (mOwnedData) {
1047        free(mOwnedData);
1048        mOwnedData = NULL;
1049    }
1050    restart();
1051}
1052
1053const ResStringPool& ResXMLTree::getStrings() const
1054{
1055    return mStrings;
1056}
1057
1058status_t ResXMLTree::validateNode(const ResXMLTree_node* node) const
1059{
1060    const uint16_t eventCode = dtohs(node->header.type);
1061
1062    status_t err = validate_chunk(
1063        &node->header, sizeof(ResXMLTree_node),
1064        mDataEnd, "ResXMLTree_node");
1065
1066    if (err >= NO_ERROR) {
1067        // Only perform additional validation on START nodes
1068        if (eventCode != RES_XML_START_ELEMENT_TYPE) {
1069            return NO_ERROR;
1070        }
1071
1072        const uint16_t headerSize = dtohs(node->header.headerSize);
1073        const uint32_t size = dtohl(node->header.size);
1074        const ResXMLTree_attrExt* attrExt = (const ResXMLTree_attrExt*)
1075            (((const uint8_t*)node) + headerSize);
1076        // check for sensical values pulled out of the stream so far...
1077        if ((size >= headerSize + sizeof(ResXMLTree_attrExt))
1078                && ((void*)attrExt > (void*)node)) {
1079            const size_t attrSize = ((size_t)dtohs(attrExt->attributeSize))
1080                * dtohs(attrExt->attributeCount);
1081            if ((dtohs(attrExt->attributeStart)+attrSize) <= (size-headerSize)) {
1082                return NO_ERROR;
1083            }
1084            LOGW("Bad XML block: node attributes use 0x%x bytes, only have 0x%x bytes\n",
1085                    (unsigned int)(dtohs(attrExt->attributeStart)+attrSize),
1086                    (unsigned int)(size-headerSize));
1087        }
1088        else {
1089            LOGW("Bad XML start block: node header size 0x%x, size 0x%x\n",
1090                (unsigned int)headerSize, (unsigned int)size);
1091        }
1092        return BAD_TYPE;
1093    }
1094
1095    return err;
1096
1097#if 0
1098    const bool isStart = dtohs(node->header.type) == RES_XML_START_ELEMENT_TYPE;
1099
1100    const uint16_t headerSize = dtohs(node->header.headerSize);
1101    const uint32_t size = dtohl(node->header.size);
1102
1103    if (headerSize >= (isStart ? sizeof(ResXMLTree_attrNode) : sizeof(ResXMLTree_node))) {
1104        if (size >= headerSize) {
1105            if (((const uint8_t*)node) <= (mDataEnd-size)) {
1106                if (!isStart) {
1107                    return NO_ERROR;
1108                }
1109                if ((((size_t)dtohs(node->attributeSize))*dtohs(node->attributeCount))
1110                        <= (size-headerSize)) {
1111                    return NO_ERROR;
1112                }
1113                LOGW("Bad XML block: node attributes use 0x%x bytes, only have 0x%x bytes\n",
1114                        ((int)dtohs(node->attributeSize))*dtohs(node->attributeCount),
1115                        (int)(size-headerSize));
1116                return BAD_TYPE;
1117            }
1118            LOGW("Bad XML block: node at 0x%x extends beyond data end 0x%x\n",
1119                    (int)(((const uint8_t*)node)-((const uint8_t*)mHeader)), (int)mSize);
1120            return BAD_TYPE;
1121        }
1122        LOGW("Bad XML block: node at 0x%x header size 0x%x smaller than total size 0x%x\n",
1123                (int)(((const uint8_t*)node)-((const uint8_t*)mHeader)),
1124                (int)headerSize, (int)size);
1125        return BAD_TYPE;
1126    }
1127    LOGW("Bad XML block: node at 0x%x header size 0x%x too small\n",
1128            (int)(((const uint8_t*)node)-((const uint8_t*)mHeader)),
1129            (int)headerSize);
1130    return BAD_TYPE;
1131#endif
1132}
1133
1134// --------------------------------------------------------------------
1135// --------------------------------------------------------------------
1136// --------------------------------------------------------------------
1137
1138struct ResTable::Header
1139{
1140    Header(ResTable* _owner) : owner(_owner), ownedData(NULL), header(NULL) { }
1141
1142    ResTable* const                 owner;
1143    void*                           ownedData;
1144    const ResTable_header*          header;
1145    size_t                          size;
1146    const uint8_t*                  dataEnd;
1147    size_t                          index;
1148    void*                           cookie;
1149
1150    ResStringPool                   values;
1151};
1152
1153struct ResTable::Type
1154{
1155    Type(const Header* _header, const Package* _package, size_t count)
1156        : header(_header), package(_package), entryCount(count),
1157          typeSpec(NULL), typeSpecFlags(NULL) { }
1158    const Header* const             header;
1159    const Package* const            package;
1160    const size_t                    entryCount;
1161    const ResTable_typeSpec*        typeSpec;
1162    const uint32_t*                 typeSpecFlags;
1163    Vector<const ResTable_type*>    configs;
1164};
1165
1166struct ResTable::Package
1167{
1168    Package(ResTable* _owner, const Header* _header, const ResTable_package* _package)
1169        : owner(_owner), header(_header), package(_package) { }
1170    ~Package()
1171    {
1172        size_t i = types.size();
1173        while (i > 0) {
1174            i--;
1175            delete types[i];
1176        }
1177    }
1178
1179    ResTable* const                 owner;
1180    const Header* const             header;
1181    const ResTable_package* const   package;
1182    Vector<Type*>                   types;
1183
1184    ResStringPool                   typeStrings;
1185    ResStringPool                   keyStrings;
1186
1187    const Type* getType(size_t idx) const {
1188        return idx < types.size() ? types[idx] : NULL;
1189    }
1190};
1191
1192// A group of objects describing a particular resource package.
1193// The first in 'package' is always the root object (from the resource
1194// table that defined the package); the ones after are skins on top of it.
1195struct ResTable::PackageGroup
1196{
1197    PackageGroup(ResTable* _owner, const String16& _name, uint32_t _id)
1198        : owner(_owner), name(_name), id(_id), typeCount(0), bags(NULL) { }
1199    ~PackageGroup() {
1200        clearBagCache();
1201        const size_t N = packages.size();
1202        for (size_t i=0; i<N; i++) {
1203            Package* pkg = packages[i];
1204            if (pkg->owner == owner) {
1205                delete pkg;
1206            }
1207        }
1208    }
1209
1210    void clearBagCache() {
1211        if (bags) {
1212            TABLE_NOISY(printf("bags=%p\n", bags));
1213            Package* pkg = packages[0];
1214            TABLE_NOISY(printf("typeCount=%x\n", typeCount));
1215            for (size_t i=0; i<typeCount; i++) {
1216                TABLE_NOISY(printf("type=%d\n", i));
1217                const Type* type = pkg->getType(i);
1218                if (type != NULL) {
1219                    bag_set** typeBags = bags[i];
1220                    TABLE_NOISY(printf("typeBags=%p\n", typeBags));
1221                    if (typeBags) {
1222                        TABLE_NOISY(printf("type->entryCount=%x\n", type->entryCount));
1223                        const size_t N = type->entryCount;
1224                        for (size_t j=0; j<N; j++) {
1225                            if (typeBags[j] && typeBags[j] != (bag_set*)0xFFFFFFFF)
1226                                free(typeBags[j]);
1227                        }
1228                        free(typeBags);
1229                    }
1230                }
1231            }
1232            free(bags);
1233            bags = NULL;
1234        }
1235    }
1236
1237    ResTable* const                 owner;
1238    String16 const                  name;
1239    uint32_t const                  id;
1240    Vector<Package*>                packages;
1241
1242    // This is for finding typeStrings and other common package stuff.
1243    Package*                        basePackage;
1244
1245    // For quick access.
1246    size_t                          typeCount;
1247
1248    // Computed attribute bags, first indexed by the type and second
1249    // by the entry in that type.
1250    bag_set***                      bags;
1251};
1252
1253struct ResTable::bag_set
1254{
1255    size_t numAttrs;    // number in array
1256    size_t availAttrs;  // total space in array
1257    uint32_t typeSpecFlags;
1258    // Followed by 'numAttr' bag_entry structures.
1259};
1260
1261ResTable::Theme::Theme(const ResTable& table)
1262    : mTable(table)
1263{
1264    memset(mPackages, 0, sizeof(mPackages));
1265}
1266
1267ResTable::Theme::~Theme()
1268{
1269    for (size_t i=0; i<Res_MAXPACKAGE; i++) {
1270        package_info* pi = mPackages[i];
1271        if (pi != NULL) {
1272            free_package(pi);
1273        }
1274    }
1275}
1276
1277void ResTable::Theme::free_package(package_info* pi)
1278{
1279    for (size_t j=0; j<pi->numTypes; j++) {
1280        theme_entry* te = pi->types[j].entries;
1281        if (te != NULL) {
1282            free(te);
1283        }
1284    }
1285    free(pi);
1286}
1287
1288ResTable::Theme::package_info* ResTable::Theme::copy_package(package_info* pi)
1289{
1290    package_info* newpi = (package_info*)malloc(
1291        sizeof(package_info) + (pi->numTypes*sizeof(type_info)));
1292    newpi->numTypes = pi->numTypes;
1293    for (size_t j=0; j<newpi->numTypes; j++) {
1294        size_t cnt = pi->types[j].numEntries;
1295        newpi->types[j].numEntries = cnt;
1296        theme_entry* te = pi->types[j].entries;
1297        if (te != NULL) {
1298            theme_entry* newte = (theme_entry*)malloc(cnt*sizeof(theme_entry));
1299            newpi->types[j].entries = newte;
1300            memcpy(newte, te, cnt*sizeof(theme_entry));
1301        } else {
1302            newpi->types[j].entries = NULL;
1303        }
1304    }
1305    return newpi;
1306}
1307
1308status_t ResTable::Theme::applyStyle(uint32_t resID, bool force)
1309{
1310    const bag_entry* bag;
1311    uint32_t bagTypeSpecFlags = 0;
1312    mTable.lock();
1313    const ssize_t N = mTable.getBagLocked(resID, &bag, &bagTypeSpecFlags);
1314    TABLE_NOISY(LOGV("Applying style 0x%08x to theme %p, count=%d", resID, this, N));
1315    if (N < 0) {
1316        mTable.unlock();
1317        return N;
1318    }
1319
1320    uint32_t curPackage = 0xffffffff;
1321    ssize_t curPackageIndex = 0;
1322    package_info* curPI = NULL;
1323    uint32_t curType = 0xffffffff;
1324    size_t numEntries = 0;
1325    theme_entry* curEntries = NULL;
1326
1327    const bag_entry* end = bag + N;
1328    while (bag < end) {
1329        const uint32_t attrRes = bag->map.name.ident;
1330        const uint32_t p = Res_GETPACKAGE(attrRes);
1331        const uint32_t t = Res_GETTYPE(attrRes);
1332        const uint32_t e = Res_GETENTRY(attrRes);
1333
1334        if (curPackage != p) {
1335            const ssize_t pidx = mTable.getResourcePackageIndex(attrRes);
1336            if (pidx < 0) {
1337                LOGE("Style contains key with bad package: 0x%08x\n", attrRes);
1338                bag++;
1339                continue;
1340            }
1341            curPackage = p;
1342            curPackageIndex = pidx;
1343            curPI = mPackages[pidx];
1344            if (curPI == NULL) {
1345                PackageGroup* const grp = mTable.mPackageGroups[pidx];
1346                int cnt = grp->typeCount;
1347                curPI = (package_info*)malloc(
1348                    sizeof(package_info) + (cnt*sizeof(type_info)));
1349                curPI->numTypes = cnt;
1350                memset(curPI->types, 0, cnt*sizeof(type_info));
1351                mPackages[pidx] = curPI;
1352            }
1353            curType = 0xffffffff;
1354        }
1355        if (curType != t) {
1356            if (t >= curPI->numTypes) {
1357                LOGE("Style contains key with bad type: 0x%08x\n", attrRes);
1358                bag++;
1359                continue;
1360            }
1361            curType = t;
1362            curEntries = curPI->types[t].entries;
1363            if (curEntries == NULL) {
1364                PackageGroup* const grp = mTable.mPackageGroups[curPackageIndex];
1365                const Type* type = grp->packages[0]->getType(t);
1366                int cnt = type != NULL ? type->entryCount : 0;
1367                curEntries = (theme_entry*)malloc(cnt*sizeof(theme_entry));
1368                memset(curEntries, Res_value::TYPE_NULL, cnt*sizeof(theme_entry));
1369                curPI->types[t].numEntries = cnt;
1370                curPI->types[t].entries = curEntries;
1371            }
1372            numEntries = curPI->types[t].numEntries;
1373        }
1374        if (e >= numEntries) {
1375            LOGE("Style contains key with bad entry: 0x%08x\n", attrRes);
1376            bag++;
1377            continue;
1378        }
1379        theme_entry* curEntry = curEntries + e;
1380        TABLE_NOISY(LOGV("Attr 0x%08x: type=0x%x, data=0x%08x; curType=0x%x",
1381                   attrRes, bag->map.value.dataType, bag->map.value.data,
1382             curEntry->value.dataType));
1383        if (force || curEntry->value.dataType == Res_value::TYPE_NULL) {
1384            curEntry->stringBlock = bag->stringBlock;
1385            curEntry->typeSpecFlags |= bagTypeSpecFlags;
1386            curEntry->value = bag->map.value;
1387        }
1388
1389        bag++;
1390    }
1391
1392    mTable.unlock();
1393
1394    //LOGI("Applying style 0x%08x (force=%d)  theme %p...\n", resID, force, this);
1395    //dumpToLog();
1396
1397    return NO_ERROR;
1398}
1399
1400status_t ResTable::Theme::setTo(const Theme& other)
1401{
1402    //LOGI("Setting theme %p from theme %p...\n", this, &other);
1403    //dumpToLog();
1404    //other.dumpToLog();
1405
1406    if (&mTable == &other.mTable) {
1407        for (size_t i=0; i<Res_MAXPACKAGE; i++) {
1408            if (mPackages[i] != NULL) {
1409                free_package(mPackages[i]);
1410            }
1411            if (other.mPackages[i] != NULL) {
1412                mPackages[i] = copy_package(other.mPackages[i]);
1413            } else {
1414                mPackages[i] = NULL;
1415            }
1416        }
1417    } else {
1418        // @todo: need to really implement this, not just copy
1419        // the system package (which is still wrong because it isn't
1420        // fixing up resource references).
1421        for (size_t i=0; i<Res_MAXPACKAGE; i++) {
1422            if (mPackages[i] != NULL) {
1423                free_package(mPackages[i]);
1424            }
1425            if (i == 0 && other.mPackages[i] != NULL) {
1426                mPackages[i] = copy_package(other.mPackages[i]);
1427            } else {
1428                mPackages[i] = NULL;
1429            }
1430        }
1431    }
1432
1433    //LOGI("Final theme:");
1434    //dumpToLog();
1435
1436    return NO_ERROR;
1437}
1438
1439ssize_t ResTable::Theme::getAttribute(uint32_t resID, Res_value* outValue,
1440        uint32_t* outTypeSpecFlags) const
1441{
1442    int cnt = 20;
1443
1444    if (outTypeSpecFlags != NULL) *outTypeSpecFlags = 0;
1445
1446    do {
1447        const ssize_t p = mTable.getResourcePackageIndex(resID);
1448        const uint32_t t = Res_GETTYPE(resID);
1449        const uint32_t e = Res_GETENTRY(resID);
1450
1451        TABLE_THEME(LOGI("Looking up attr 0x%08x in theme %p", resID, this));
1452
1453        if (p >= 0) {
1454            const package_info* const pi = mPackages[p];
1455            TABLE_THEME(LOGI("Found package: %p", pi));
1456            if (pi != NULL) {
1457                TABLE_THEME(LOGI("Desired type index is %ld in avail %d", t, pi->numTypes));
1458                if (t < pi->numTypes) {
1459                    const type_info& ti = pi->types[t];
1460                    TABLE_THEME(LOGI("Desired entry index is %ld in avail %d", e, ti.numEntries));
1461                    if (e < ti.numEntries) {
1462                        const theme_entry& te = ti.entries[e];
1463                        if (outTypeSpecFlags != NULL) {
1464                            *outTypeSpecFlags |= te.typeSpecFlags;
1465                        }
1466                        TABLE_THEME(LOGI("Theme value: type=0x%x, data=0x%08x",
1467                                te.value.dataType, te.value.data));
1468                        const uint8_t type = te.value.dataType;
1469                        if (type == Res_value::TYPE_ATTRIBUTE) {
1470                            if (cnt > 0) {
1471                                cnt--;
1472                                resID = te.value.data;
1473                                continue;
1474                            }
1475                            LOGW("Too many attribute references, stopped at: 0x%08x\n", resID);
1476                            return BAD_INDEX;
1477                        } else if (type != Res_value::TYPE_NULL) {
1478                            *outValue = te.value;
1479                            return te.stringBlock;
1480                        }
1481                        return BAD_INDEX;
1482                    }
1483                }
1484            }
1485        }
1486        break;
1487
1488    } while (true);
1489
1490    return BAD_INDEX;
1491}
1492
1493ssize_t ResTable::Theme::resolveAttributeReference(Res_value* inOutValue,
1494        ssize_t blockIndex, uint32_t* outLastRef,
1495        uint32_t* inoutTypeSpecFlags, ResTable_config* inoutConfig) const
1496{
1497    //printf("Resolving type=0x%x\n", inOutValue->dataType);
1498    if (inOutValue->dataType == Res_value::TYPE_ATTRIBUTE) {
1499        uint32_t newTypeSpecFlags;
1500        blockIndex = getAttribute(inOutValue->data, inOutValue, &newTypeSpecFlags);
1501        TABLE_THEME(LOGI("Resolving attr reference: blockIndex=%d, type=0x%x, data=%p\n",
1502             (int)blockIndex, (int)inOutValue->dataType, (void*)inOutValue->data));
1503        if (inoutTypeSpecFlags != NULL) *inoutTypeSpecFlags |= newTypeSpecFlags;
1504        //printf("Retrieved attribute new type=0x%x\n", inOutValue->dataType);
1505        if (blockIndex < 0) {
1506            return blockIndex;
1507        }
1508    }
1509    return mTable.resolveReference(inOutValue, blockIndex, outLastRef,
1510            inoutTypeSpecFlags, inoutConfig);
1511}
1512
1513void ResTable::Theme::dumpToLog() const
1514{
1515    LOGI("Theme %p:\n", this);
1516    for (size_t i=0; i<Res_MAXPACKAGE; i++) {
1517        package_info* pi = mPackages[i];
1518        if (pi == NULL) continue;
1519
1520        LOGI("  Package #0x%02x:\n", (int)(i+1));
1521        for (size_t j=0; j<pi->numTypes; j++) {
1522            type_info& ti = pi->types[j];
1523            if (ti.numEntries == 0) continue;
1524
1525            LOGI("    Type #0x%02x:\n", (int)(j+1));
1526            for (size_t k=0; k<ti.numEntries; k++) {
1527                theme_entry& te = ti.entries[k];
1528                if (te.value.dataType == Res_value::TYPE_NULL) continue;
1529                LOGI("      0x%08x: t=0x%x, d=0x%08x (block=%d)\n",
1530                     (int)Res_MAKEID(i, j, k),
1531                     te.value.dataType, (int)te.value.data, (int)te.stringBlock);
1532            }
1533        }
1534    }
1535}
1536
1537ResTable::ResTable()
1538    : mError(NO_INIT)
1539{
1540    memset(&mParams, 0, sizeof(mParams));
1541    memset(mPackageMap, 0, sizeof(mPackageMap));
1542    //LOGI("Creating ResTable %p\n", this);
1543}
1544
1545ResTable::ResTable(const void* data, size_t size, void* cookie, bool copyData)
1546    : mError(NO_INIT)
1547{
1548    memset(&mParams, 0, sizeof(mParams));
1549    memset(mPackageMap, 0, sizeof(mPackageMap));
1550    add(data, size, cookie, copyData);
1551    LOG_FATAL_IF(mError != NO_ERROR, "Error parsing resource table");
1552    //LOGI("Creating ResTable %p\n", this);
1553}
1554
1555ResTable::~ResTable()
1556{
1557    //LOGI("Destroying ResTable in %p\n", this);
1558    uninit();
1559}
1560
1561inline ssize_t ResTable::getResourcePackageIndex(uint32_t resID) const
1562{
1563    return ((ssize_t)mPackageMap[Res_GETPACKAGE(resID)+1])-1;
1564}
1565
1566status_t ResTable::add(const void* data, size_t size, void* cookie, bool copyData)
1567{
1568    return add(data, size, cookie, NULL, copyData);
1569}
1570
1571status_t ResTable::add(Asset* asset, void* cookie, bool copyData)
1572{
1573    const void* data = asset->getBuffer(true);
1574    if (data == NULL) {
1575        LOGW("Unable to get buffer of resource asset file");
1576        return UNKNOWN_ERROR;
1577    }
1578    size_t size = (size_t)asset->getLength();
1579    return add(data, size, cookie, asset, copyData);
1580}
1581
1582status_t ResTable::add(ResTable* src)
1583{
1584    mError = src->mError;
1585
1586    for (size_t i=0; i<src->mHeaders.size(); i++) {
1587        mHeaders.add(src->mHeaders[i]);
1588    }
1589
1590    for (size_t i=0; i<src->mPackageGroups.size(); i++) {
1591        PackageGroup* srcPg = src->mPackageGroups[i];
1592        PackageGroup* pg = new PackageGroup(this, srcPg->name, srcPg->id);
1593        for (size_t j=0; j<srcPg->packages.size(); j++) {
1594            pg->packages.add(srcPg->packages[j]);
1595        }
1596        pg->basePackage = srcPg->basePackage;
1597        pg->typeCount = srcPg->typeCount;
1598        mPackageGroups.add(pg);
1599    }
1600
1601    memcpy(mPackageMap, src->mPackageMap, sizeof(mPackageMap));
1602
1603    return mError;
1604}
1605
1606status_t ResTable::add(const void* data, size_t size, void* cookie,
1607                       Asset* asset, bool copyData)
1608{
1609    if (!data) return NO_ERROR;
1610    Header* header = new Header(this);
1611    header->index = mHeaders.size();
1612    header->cookie = cookie;
1613    mHeaders.add(header);
1614
1615    const bool notDeviceEndian = htods(0xf0) != 0xf0;
1616
1617    LOAD_TABLE_NOISY(
1618        LOGV("Adding resources to ResTable: data=%p, size=0x%x, cookie=%p, asset=%p, copy=%d\n",
1619             data, size, cookie, asset, copyData));
1620
1621    if (copyData || notDeviceEndian) {
1622        header->ownedData = malloc(size);
1623        if (header->ownedData == NULL) {
1624            return (mError=NO_MEMORY);
1625        }
1626        memcpy(header->ownedData, data, size);
1627        data = header->ownedData;
1628    }
1629
1630    header->header = (const ResTable_header*)data;
1631    header->size = dtohl(header->header->header.size);
1632    //LOGI("Got size 0x%x, again size 0x%x, raw size 0x%x\n", header->size,
1633    //     dtohl(header->header->header.size), header->header->header.size);
1634    LOAD_TABLE_NOISY(LOGV("Loading ResTable @%p:\n", header->header));
1635    LOAD_TABLE_NOISY(printHexData(2, header->header, header->size < 256 ? header->size : 256,
1636                                  16, 16, 0, false, printToLogFunc));
1637    if (dtohs(header->header->header.headerSize) > header->size
1638            || header->size > size) {
1639        LOGW("Bad resource table: header size 0x%x or total size 0x%x is larger than data size 0x%x\n",
1640             (int)dtohs(header->header->header.headerSize),
1641             (int)header->size, (int)size);
1642        return (mError=BAD_TYPE);
1643    }
1644    if (((dtohs(header->header->header.headerSize)|header->size)&0x3) != 0) {
1645        LOGW("Bad resource table: header size 0x%x or total size 0x%x is not on an integer boundary\n",
1646             (int)dtohs(header->header->header.headerSize),
1647             (int)header->size);
1648        return (mError=BAD_TYPE);
1649    }
1650    header->dataEnd = ((const uint8_t*)header->header) + header->size;
1651
1652    // Iterate through all chunks.
1653    size_t curPackage = 0;
1654
1655    const ResChunk_header* chunk =
1656        (const ResChunk_header*)(((const uint8_t*)header->header)
1657                                 + dtohs(header->header->header.headerSize));
1658    while (((const uint8_t*)chunk) <= (header->dataEnd-sizeof(ResChunk_header)) &&
1659           ((const uint8_t*)chunk) <= (header->dataEnd-dtohl(chunk->size))) {
1660        status_t err = validate_chunk(chunk, sizeof(ResChunk_header), header->dataEnd, "ResTable");
1661        if (err != NO_ERROR) {
1662            return (mError=err);
1663        }
1664        TABLE_NOISY(LOGV("Chunk: type=0x%x, headerSize=0x%x, size=0x%x, pos=%p\n",
1665                     dtohs(chunk->type), dtohs(chunk->headerSize), dtohl(chunk->size),
1666                     (void*)(((const uint8_t*)chunk) - ((const uint8_t*)header->header))));
1667        const size_t csize = dtohl(chunk->size);
1668        const uint16_t ctype = dtohs(chunk->type);
1669        if (ctype == RES_STRING_POOL_TYPE) {
1670            if (header->values.getError() != NO_ERROR) {
1671                // Only use the first string chunk; ignore any others that
1672                // may appear.
1673                status_t err = header->values.setTo(chunk, csize);
1674                if (err != NO_ERROR) {
1675                    return (mError=err);
1676                }
1677            } else {
1678                LOGW("Multiple string chunks found in resource table.");
1679            }
1680        } else if (ctype == RES_TABLE_PACKAGE_TYPE) {
1681            if (curPackage >= dtohl(header->header->packageCount)) {
1682                LOGW("More package chunks were found than the %d declared in the header.",
1683                     dtohl(header->header->packageCount));
1684                return (mError=BAD_TYPE);
1685            }
1686            if (parsePackage((ResTable_package*)chunk, header) != NO_ERROR) {
1687                return mError;
1688            }
1689            curPackage++;
1690        } else {
1691            LOGW("Unknown chunk type %p in table at %p.\n",
1692                 (void*)(int)(ctype),
1693                 (void*)(((const uint8_t*)chunk) - ((const uint8_t*)header->header)));
1694        }
1695        chunk = (const ResChunk_header*)
1696            (((const uint8_t*)chunk) + csize);
1697    }
1698
1699    if (curPackage < dtohl(header->header->packageCount)) {
1700        LOGW("Fewer package chunks (%d) were found than the %d declared in the header.",
1701             (int)curPackage, dtohl(header->header->packageCount));
1702        return (mError=BAD_TYPE);
1703    }
1704    mError = header->values.getError();
1705    if (mError != NO_ERROR) {
1706        LOGW("No string values found in resource table!");
1707    }
1708    TABLE_NOISY(LOGV("Returning from add with mError=%d\n", mError));
1709    return mError;
1710}
1711
1712status_t ResTable::getError() const
1713{
1714    return mError;
1715}
1716
1717void ResTable::uninit()
1718{
1719    mError = NO_INIT;
1720    size_t N = mPackageGroups.size();
1721    for (size_t i=0; i<N; i++) {
1722        PackageGroup* g = mPackageGroups[i];
1723        delete g;
1724    }
1725    N = mHeaders.size();
1726    for (size_t i=0; i<N; i++) {
1727        Header* header = mHeaders[i];
1728        if (header->owner == this) {
1729            if (header->ownedData) {
1730                free(header->ownedData);
1731            }
1732            delete header;
1733        }
1734    }
1735
1736    mPackageGroups.clear();
1737    mHeaders.clear();
1738}
1739
1740bool ResTable::getResourceName(uint32_t resID, resource_name* outName) const
1741{
1742    if (mError != NO_ERROR) {
1743        return false;
1744    }
1745
1746    const ssize_t p = getResourcePackageIndex(resID);
1747    const int t = Res_GETTYPE(resID);
1748    const int e = Res_GETENTRY(resID);
1749
1750    if (p < 0) {
1751        if (Res_GETPACKAGE(resID)+1 == 0) {
1752            LOGW("No package identifier when getting name for resource number 0x%08x", resID);
1753        } else {
1754            LOGW("Resources don't contain package for resource number 0x%08x", resID);
1755        }
1756        return false;
1757    }
1758    if (t < 0) {
1759        LOGW("No type identifier when getting name for resource number 0x%08x", resID);
1760        return false;
1761    }
1762
1763    const PackageGroup* const grp = mPackageGroups[p];
1764    if (grp == NULL) {
1765        LOGW("Bad identifier when getting name for resource number 0x%08x", resID);
1766        return false;
1767    }
1768    if (grp->packages.size() > 0) {
1769        const Package* const package = grp->packages[0];
1770
1771        const ResTable_type* type;
1772        const ResTable_entry* entry;
1773        ssize_t offset = getEntry(package, t, e, NULL, &type, &entry, NULL);
1774        if (offset <= 0) {
1775            return false;
1776        }
1777
1778        outName->package = grp->name.string();
1779        outName->packageLen = grp->name.size();
1780        outName->type = grp->basePackage->typeStrings.stringAt(t, &outName->typeLen);
1781        outName->name = grp->basePackage->keyStrings.stringAt(
1782            dtohl(entry->key.index), &outName->nameLen);
1783        return true;
1784    }
1785
1786    return false;
1787}
1788
1789ssize_t ResTable::getResource(uint32_t resID, Res_value* outValue, bool mayBeBag,
1790        uint32_t* outSpecFlags, ResTable_config* outConfig) const
1791{
1792    if (mError != NO_ERROR) {
1793        return mError;
1794    }
1795
1796    const ssize_t p = getResourcePackageIndex(resID);
1797    const int t = Res_GETTYPE(resID);
1798    const int e = Res_GETENTRY(resID);
1799
1800    if (p < 0) {
1801        if (Res_GETPACKAGE(resID)+1 == 0) {
1802            LOGW("No package identifier when getting name for resource number 0x%08x", resID);
1803        } else {
1804            LOGW("Resources don't contain package for resource number 0x%08x", resID);
1805        }
1806        return BAD_INDEX;
1807    }
1808    if (t < 0) {
1809        LOGW("No type identifier when getting value for resource number 0x%08x", resID);
1810        return BAD_INDEX;
1811    }
1812
1813    const Res_value* bestValue = NULL;
1814    const Package* bestPackage = NULL;
1815    ResTable_config bestItem;
1816    memset(&bestItem, 0, sizeof(bestItem)); // make the compiler shut up
1817
1818    if (outSpecFlags != NULL) *outSpecFlags = 0;
1819
1820    // Look through all resource packages, starting with the most
1821    // recently added.
1822    const PackageGroup* const grp = mPackageGroups[p];
1823    if (grp == NULL) {
1824        LOGW("Bad identifier when getting value for resource number 0x%08x", resID);
1825        return false;
1826    }
1827    size_t ip = grp->packages.size();
1828    while (ip > 0) {
1829        ip--;
1830
1831        const Package* const package = grp->packages[ip];
1832
1833        const ResTable_type* type;
1834        const ResTable_entry* entry;
1835        const Type* typeClass;
1836        ssize_t offset = getEntry(package, t, e, &mParams, &type, &entry, &typeClass);
1837        if (offset <= 0) {
1838            if (offset < 0) {
1839                LOGW("Failure getting entry for 0x%08x (t=%d e=%d) in package %d: 0x%08x\n",
1840                        resID, t, e, (int)ip, (int)offset);
1841                return offset;
1842            }
1843            continue;
1844        }
1845
1846        if ((dtohs(entry->flags)&entry->FLAG_COMPLEX) != 0) {
1847            if (!mayBeBag) {
1848                LOGW("Requesting resource %p failed because it is complex\n",
1849                     (void*)resID);
1850            }
1851            continue;
1852        }
1853
1854        TABLE_NOISY(aout << "Resource type data: "
1855              << HexDump(type, dtohl(type->header.size)) << endl);
1856
1857        if ((size_t)offset > (dtohl(type->header.size)-sizeof(Res_value))) {
1858            LOGW("ResTable_item at %d is beyond type chunk data %d",
1859                 (int)offset, dtohl(type->header.size));
1860            return BAD_TYPE;
1861        }
1862
1863        const Res_value* item =
1864            (const Res_value*)(((const uint8_t*)type) + offset);
1865        ResTable_config thisConfig;
1866        thisConfig.copyFromDtoH(type->config);
1867
1868        if (outSpecFlags != NULL) {
1869            if (typeClass->typeSpecFlags != NULL) {
1870                *outSpecFlags |= dtohl(typeClass->typeSpecFlags[e]);
1871            } else {
1872                *outSpecFlags = -1;
1873            }
1874        }
1875
1876        if (bestPackage != NULL && bestItem.isMoreSpecificThan(thisConfig)) {
1877            continue;
1878        }
1879
1880        bestItem = thisConfig;
1881        bestValue = item;
1882        bestPackage = package;
1883    }
1884
1885    TABLE_NOISY(printf("Found result: package %p\n", bestPackage));
1886
1887    if (bestValue) {
1888        outValue->size = dtohs(bestValue->size);
1889        outValue->res0 = bestValue->res0;
1890        outValue->dataType = bestValue->dataType;
1891        outValue->data = dtohl(bestValue->data);
1892        if (outConfig != NULL) {
1893            *outConfig = bestItem;
1894        }
1895        TABLE_NOISY(size_t len;
1896              printf("Found value: pkg=%d, type=%d, str=%s, int=%d\n",
1897                     bestPackage->header->index,
1898                     outValue->dataType,
1899                     outValue->dataType == bestValue->TYPE_STRING
1900                     ? String8(bestPackage->header->values.stringAt(
1901                         outValue->data, &len)).string()
1902                     : "",
1903                     outValue->data));
1904        return bestPackage->header->index;
1905    }
1906
1907    return BAD_INDEX;
1908}
1909
1910ssize_t ResTable::resolveReference(Res_value* value, ssize_t blockIndex,
1911        uint32_t* outLastRef, uint32_t* inoutTypeSpecFlags,
1912        ResTable_config* outConfig) const
1913{
1914    int count=0;
1915    while (blockIndex >= 0 && value->dataType == value->TYPE_REFERENCE
1916           && value->data != 0 && count < 20) {
1917        if (outLastRef) *outLastRef = value->data;
1918        uint32_t lastRef = value->data;
1919        uint32_t newFlags = 0;
1920        const ssize_t newIndex = getResource(value->data, value, true, &newFlags,
1921                outConfig);
1922        TABLE_THEME(LOGI("Resolving reference %p: newIndex=%d, type=0x%x, data=%p\n",
1923             (void*)lastRef, (int)newIndex, (int)value->dataType, (void*)value->data));
1924        //printf("Getting reference 0x%08x: newIndex=%d\n", value->data, newIndex);
1925        if (inoutTypeSpecFlags != NULL) *inoutTypeSpecFlags |= newFlags;
1926        if (newIndex < 0) {
1927            // This can fail if the resource being referenced is a style...
1928            // in this case, just return the reference, and expect the
1929            // caller to deal with.
1930            return blockIndex;
1931        }
1932        blockIndex = newIndex;
1933        count++;
1934    }
1935    return blockIndex;
1936}
1937
1938const char16_t* ResTable::valueToString(
1939    const Res_value* value, size_t stringBlock,
1940    char16_t tmpBuffer[TMP_BUFFER_SIZE], size_t* outLen)
1941{
1942    if (!value) {
1943        return NULL;
1944    }
1945    if (value->dataType == value->TYPE_STRING) {
1946        return getTableStringBlock(stringBlock)->stringAt(value->data, outLen);
1947    }
1948    // XXX do int to string conversions.
1949    return NULL;
1950}
1951
1952ssize_t ResTable::lockBag(uint32_t resID, const bag_entry** outBag) const
1953{
1954    mLock.lock();
1955    ssize_t err = getBagLocked(resID, outBag);
1956    if (err < NO_ERROR) {
1957        //printf("*** get failed!  unlocking\n");
1958        mLock.unlock();
1959    }
1960    return err;
1961}
1962
1963void ResTable::unlockBag(const bag_entry* bag) const
1964{
1965    //printf("<<< unlockBag %p\n", this);
1966    mLock.unlock();
1967}
1968
1969void ResTable::lock() const
1970{
1971    mLock.lock();
1972}
1973
1974void ResTable::unlock() const
1975{
1976    mLock.unlock();
1977}
1978
1979ssize_t ResTable::getBagLocked(uint32_t resID, const bag_entry** outBag,
1980        uint32_t* outTypeSpecFlags) const
1981{
1982    if (mError != NO_ERROR) {
1983        return mError;
1984    }
1985
1986    const ssize_t p = getResourcePackageIndex(resID);
1987    const int t = Res_GETTYPE(resID);
1988    const int e = Res_GETENTRY(resID);
1989
1990    if (p < 0) {
1991        LOGW("Invalid package identifier when getting bag for resource number 0x%08x", resID);
1992        return BAD_INDEX;
1993    }
1994    if (t < 0) {
1995        LOGW("No type identifier when getting bag for resource number 0x%08x", resID);
1996        return BAD_INDEX;
1997    }
1998
1999    //printf("Get bag: id=0x%08x, p=%d, t=%d\n", resID, p, t);
2000    PackageGroup* const grp = mPackageGroups[p];
2001    if (grp == NULL) {
2002        LOGW("Bad identifier when getting bag for resource number 0x%08x", resID);
2003        return false;
2004    }
2005
2006    if (t >= (int)grp->typeCount) {
2007        LOGW("Type identifier 0x%x is larger than type count 0x%x",
2008             t+1, (int)grp->typeCount);
2009        return BAD_INDEX;
2010    }
2011
2012    const Package* const basePackage = grp->packages[0];
2013
2014    const Type* const typeConfigs = basePackage->getType(t);
2015
2016    const size_t NENTRY = typeConfigs->entryCount;
2017    if (e >= (int)NENTRY) {
2018        LOGW("Entry identifier 0x%x is larger than entry count 0x%x",
2019             e, (int)typeConfigs->entryCount);
2020        return BAD_INDEX;
2021    }
2022
2023    // First see if we've already computed this bag...
2024    if (grp->bags) {
2025        bag_set** typeSet = grp->bags[t];
2026        if (typeSet) {
2027            bag_set* set = typeSet[e];
2028            if (set) {
2029                if (set != (bag_set*)0xFFFFFFFF) {
2030                    if (outTypeSpecFlags != NULL) {
2031                        *outTypeSpecFlags = set->typeSpecFlags;
2032                    }
2033                    *outBag = (bag_entry*)(set+1);
2034                    //LOGI("Found existing bag for: %p\n", (void*)resID);
2035                    return set->numAttrs;
2036                }
2037                LOGW("Attempt to retrieve bag 0x%08x which is invalid or in a cycle.",
2038                     resID);
2039                return BAD_INDEX;
2040            }
2041        }
2042    }
2043
2044    // Bag not found, we need to compute it!
2045    if (!grp->bags) {
2046        grp->bags = (bag_set***)malloc(sizeof(bag_set*)*grp->typeCount);
2047        if (!grp->bags) return NO_MEMORY;
2048        memset(grp->bags, 0, sizeof(bag_set*)*grp->typeCount);
2049    }
2050
2051    bag_set** typeSet = grp->bags[t];
2052    if (!typeSet) {
2053        typeSet = (bag_set**)malloc(sizeof(bag_set*)*NENTRY);
2054        if (!typeSet) return NO_MEMORY;
2055        memset(typeSet, 0, sizeof(bag_set*)*NENTRY);
2056        grp->bags[t] = typeSet;
2057    }
2058
2059    // Mark that we are currently working on this one.
2060    typeSet[e] = (bag_set*)0xFFFFFFFF;
2061
2062    // This is what we are building.
2063    bag_set* set = NULL;
2064
2065    TABLE_NOISY(LOGI("Building bag: %p\n", (void*)resID));
2066
2067    // Now collect all bag attributes from all packages.
2068    size_t ip = grp->packages.size();
2069    while (ip > 0) {
2070        ip--;
2071
2072        const Package* const package = grp->packages[ip];
2073
2074        const ResTable_type* type;
2075        const ResTable_entry* entry;
2076        const Type* typeClass;
2077        LOGV("Getting entry pkg=%p, t=%d, e=%d\n", package, t, e);
2078        ssize_t offset = getEntry(package, t, e, &mParams, &type, &entry, &typeClass);
2079        LOGV("Resulting offset=%d\n", offset);
2080        if (offset <= 0) {
2081            if (offset < 0) {
2082                if (set) free(set);
2083                return offset;
2084            }
2085            continue;
2086        }
2087
2088        if ((dtohs(entry->flags)&entry->FLAG_COMPLEX) == 0) {
2089            LOGW("Skipping entry %p in package table %d because it is not complex!\n",
2090                 (void*)resID, (int)ip);
2091            continue;
2092        }
2093
2094        const uint16_t entrySize = dtohs(entry->size);
2095        const uint32_t parent = entrySize >= sizeof(ResTable_map_entry)
2096            ? dtohl(((const ResTable_map_entry*)entry)->parent.ident) : 0;
2097        const uint32_t count = entrySize >= sizeof(ResTable_map_entry)
2098            ? dtohl(((const ResTable_map_entry*)entry)->count) : 0;
2099
2100        size_t N = count;
2101
2102        TABLE_NOISY(LOGI("Found map: size=%p parent=%p count=%d\n",
2103                         entrySize, parent, count));
2104
2105        if (set == NULL) {
2106            // If this map inherits from another, we need to start
2107            // with its parent's values.  Otherwise start out empty.
2108            TABLE_NOISY(printf("Creating new bag, entrySize=0x%08x, parent=0x%08x\n",
2109                         entrySize, parent));
2110            if (parent) {
2111                const bag_entry* parentBag;
2112                uint32_t parentTypeSpecFlags = 0;
2113                const ssize_t NP = getBagLocked(parent, &parentBag, &parentTypeSpecFlags);
2114                const size_t NT = ((NP >= 0) ? NP : 0) + N;
2115                set = (bag_set*)malloc(sizeof(bag_set)+sizeof(bag_entry)*NT);
2116                if (set == NULL) {
2117                    return NO_MEMORY;
2118                }
2119                if (NP > 0) {
2120                    memcpy(set+1, parentBag, NP*sizeof(bag_entry));
2121                    set->numAttrs = NP;
2122                    TABLE_NOISY(LOGI("Initialized new bag with %d inherited attributes.\n", NP));
2123                } else {
2124                    TABLE_NOISY(LOGI("Initialized new bag with no inherited attributes.\n"));
2125                    set->numAttrs = 0;
2126                }
2127                set->availAttrs = NT;
2128                set->typeSpecFlags = parentTypeSpecFlags;
2129            } else {
2130                set = (bag_set*)malloc(sizeof(bag_set)+sizeof(bag_entry)*N);
2131                if (set == NULL) {
2132                    return NO_MEMORY;
2133                }
2134                set->numAttrs = 0;
2135                set->availAttrs = N;
2136                set->typeSpecFlags = 0;
2137            }
2138        }
2139
2140        if (typeClass->typeSpecFlags != NULL) {
2141            set->typeSpecFlags |= dtohl(typeClass->typeSpecFlags[e]);
2142        } else {
2143            set->typeSpecFlags = -1;
2144        }
2145
2146        // Now merge in the new attributes...
2147        ssize_t curOff = offset;
2148        const ResTable_map* map;
2149        bag_entry* entries = (bag_entry*)(set+1);
2150        size_t curEntry = 0;
2151        uint32_t pos = 0;
2152        TABLE_NOISY(LOGI("Starting with set %p, entries=%p, avail=%d\n",
2153                     set, entries, set->availAttrs));
2154        while (pos < count) {
2155            TABLE_NOISY(printf("Now at %p\n", (void*)curOff));
2156
2157            if ((size_t)curOff > (dtohl(type->header.size)-sizeof(ResTable_map))) {
2158                LOGW("ResTable_map at %d is beyond type chunk data %d",
2159                     (int)curOff, dtohl(type->header.size));
2160                return BAD_TYPE;
2161            }
2162            map = (const ResTable_map*)(((const uint8_t*)type) + curOff);
2163            N++;
2164
2165            const uint32_t newName = htodl(map->name.ident);
2166            bool isInside;
2167            uint32_t oldName = 0;
2168            while ((isInside=(curEntry < set->numAttrs))
2169                    && (oldName=entries[curEntry].map.name.ident) < newName) {
2170                TABLE_NOISY(printf("#%d: Keeping existing attribute: 0x%08x\n",
2171                             curEntry, entries[curEntry].map.name.ident));
2172                curEntry++;
2173            }
2174
2175            if ((!isInside) || oldName != newName) {
2176                // This is a new attribute...  figure out what to do with it.
2177                if (set->numAttrs >= set->availAttrs) {
2178                    // Need to alloc more memory...
2179                    const size_t newAvail = set->availAttrs+N;
2180                    set = (bag_set*)realloc(set,
2181                                            sizeof(bag_set)
2182                                            + sizeof(bag_entry)*newAvail);
2183                    if (set == NULL) {
2184                        return NO_MEMORY;
2185                    }
2186                    set->availAttrs = newAvail;
2187                    entries = (bag_entry*)(set+1);
2188                    TABLE_NOISY(printf("Reallocated set %p, entries=%p, avail=%d\n",
2189                                 set, entries, set->availAttrs));
2190                }
2191                if (isInside) {
2192                    // Going in the middle, need to make space.
2193                    memmove(entries+curEntry+1, entries+curEntry,
2194                            sizeof(bag_entry)*(set->numAttrs-curEntry));
2195                    set->numAttrs++;
2196                }
2197                TABLE_NOISY(printf("#%d: Inserting new attribute: 0x%08x\n",
2198                             curEntry, newName));
2199            } else {
2200                TABLE_NOISY(printf("#%d: Replacing existing attribute: 0x%08x\n",
2201                             curEntry, oldName));
2202            }
2203
2204            bag_entry* cur = entries+curEntry;
2205
2206            cur->stringBlock = package->header->index;
2207            cur->map.name.ident = newName;
2208            cur->map.value.copyFrom_dtoh(map->value);
2209            TABLE_NOISY(printf("Setting entry #%d %p: block=%d, name=0x%08x, type=%d, data=0x%08x\n",
2210                         curEntry, cur, cur->stringBlock, cur->map.name.ident,
2211                         cur->map.value.dataType, cur->map.value.data));
2212
2213            // On to the next!
2214            curEntry++;
2215            pos++;
2216            const size_t size = dtohs(map->value.size);
2217            curOff += size + sizeof(*map)-sizeof(map->value);
2218        };
2219        if (curEntry > set->numAttrs) {
2220            set->numAttrs = curEntry;
2221        }
2222    }
2223
2224    // And this is it...
2225    typeSet[e] = set;
2226    if (set) {
2227        if (outTypeSpecFlags != NULL) {
2228            *outTypeSpecFlags = set->typeSpecFlags;
2229        }
2230        *outBag = (bag_entry*)(set+1);
2231        TABLE_NOISY(LOGI("Returning %d attrs\n", set->numAttrs));
2232        return set->numAttrs;
2233    }
2234    return BAD_INDEX;
2235}
2236
2237void ResTable::setParameters(const ResTable_config* params)
2238{
2239    mLock.lock();
2240    TABLE_GETENTRY(LOGI("Setting parameters: imsi:%d/%d lang:%c%c cnt:%c%c "
2241                        "orien:%d touch:%d density:%d key:%d inp:%d nav:%d w:%d h:%d\n",
2242                       params->mcc, params->mnc,
2243                       params->language[0] ? params->language[0] : '-',
2244                       params->language[1] ? params->language[1] : '-',
2245                       params->country[0] ? params->country[0] : '-',
2246                       params->country[1] ? params->country[1] : '-',
2247                       params->orientation,
2248                       params->touchscreen,
2249                       params->density,
2250                       params->keyboard,
2251                       params->inputFlags,
2252                       params->navigation,
2253                       params->screenWidth,
2254                       params->screenHeight));
2255    mParams = *params;
2256    for (size_t i=0; i<mPackageGroups.size(); i++) {
2257        TABLE_NOISY(LOGI("CLEARING BAGS FOR GROUP %d!", i));
2258        mPackageGroups[i]->clearBagCache();
2259    }
2260    mLock.unlock();
2261}
2262
2263void ResTable::getParameters(ResTable_config* params) const
2264{
2265    mLock.lock();
2266    *params = mParams;
2267    mLock.unlock();
2268}
2269
2270struct id_name_map {
2271    uint32_t id;
2272    size_t len;
2273    char16_t name[6];
2274};
2275
2276const static id_name_map ID_NAMES[] = {
2277    { ResTable_map::ATTR_TYPE,  5, { '^', 't', 'y', 'p', 'e' } },
2278    { ResTable_map::ATTR_L10N,  5, { '^', 'l', '1', '0', 'n' } },
2279    { ResTable_map::ATTR_MIN,   4, { '^', 'm', 'i', 'n' } },
2280    { ResTable_map::ATTR_MAX,   4, { '^', 'm', 'a', 'x' } },
2281    { ResTable_map::ATTR_OTHER, 6, { '^', 'o', 't', 'h', 'e', 'r' } },
2282    { ResTable_map::ATTR_ZERO,  5, { '^', 'z', 'e', 'r', 'o' } },
2283    { ResTable_map::ATTR_ONE,   4, { '^', 'o', 'n', 'e' } },
2284    { ResTable_map::ATTR_TWO,   4, { '^', 't', 'w', 'o' } },
2285    { ResTable_map::ATTR_FEW,   4, { '^', 'f', 'e', 'w' } },
2286    { ResTable_map::ATTR_MANY,  5, { '^', 'm', 'a', 'n', 'y' } },
2287};
2288
2289uint32_t ResTable::identifierForName(const char16_t* name, size_t nameLen,
2290                                     const char16_t* type, size_t typeLen,
2291                                     const char16_t* package,
2292                                     size_t packageLen,
2293                                     uint32_t* outTypeSpecFlags) const
2294{
2295    TABLE_SUPER_NOISY(printf("Identifier for name: error=%d\n", mError));
2296
2297    // Check for internal resource identifier as the very first thing, so
2298    // that we will always find them even when there are no resources.
2299    if (name[0] == '^') {
2300        const int N = (sizeof(ID_NAMES)/sizeof(ID_NAMES[0]));
2301        size_t len;
2302        for (int i=0; i<N; i++) {
2303            const id_name_map* m = ID_NAMES + i;
2304            len = m->len;
2305            if (len != nameLen) {
2306                continue;
2307            }
2308            for (size_t j=1; j<len; j++) {
2309                if (m->name[j] != name[j]) {
2310                    goto nope;
2311                }
2312            }
2313            return m->id;
2314nope:
2315            ;
2316        }
2317        if (nameLen > 7) {
2318            if (name[1] == 'i' && name[2] == 'n'
2319                && name[3] == 'd' && name[4] == 'e' && name[5] == 'x'
2320                && name[6] == '_') {
2321                int index = atoi(String8(name + 7, nameLen - 7).string());
2322                if (Res_CHECKID(index)) {
2323                    LOGW("Array resource index: %d is too large.",
2324                         index);
2325                    return 0;
2326                }
2327                return  Res_MAKEARRAY(index);
2328            }
2329        }
2330        return 0;
2331    }
2332
2333    if (mError != NO_ERROR) {
2334        return 0;
2335    }
2336
2337    // Figure out the package and type we are looking in...
2338
2339    const char16_t* packageEnd = NULL;
2340    const char16_t* typeEnd = NULL;
2341    const char16_t* const nameEnd = name+nameLen;
2342    const char16_t* p = name;
2343    while (p < nameEnd) {
2344        if (*p == ':') packageEnd = p;
2345        else if (*p == '/') typeEnd = p;
2346        p++;
2347    }
2348    if (*name == '@') name++;
2349    if (name >= nameEnd) {
2350        return 0;
2351    }
2352
2353    if (packageEnd) {
2354        package = name;
2355        packageLen = packageEnd-name;
2356        name = packageEnd+1;
2357    } else if (!package) {
2358        return 0;
2359    }
2360
2361    if (typeEnd) {
2362        type = name;
2363        typeLen = typeEnd-name;
2364        name = typeEnd+1;
2365    } else if (!type) {
2366        return 0;
2367    }
2368
2369    if (name >= nameEnd) {
2370        return 0;
2371    }
2372    nameLen = nameEnd-name;
2373
2374    TABLE_NOISY(printf("Looking for identifier: type=%s, name=%s, package=%s\n",
2375                 String8(type, typeLen).string(),
2376                 String8(name, nameLen).string(),
2377                 String8(package, packageLen).string()));
2378
2379    const size_t NG = mPackageGroups.size();
2380    for (size_t ig=0; ig<NG; ig++) {
2381        const PackageGroup* group = mPackageGroups[ig];
2382
2383        if (strzcmp16(package, packageLen,
2384                      group->name.string(), group->name.size())) {
2385            TABLE_NOISY(printf("Skipping package group: %s\n", String8(group->name).string()));
2386            continue;
2387        }
2388
2389        const ssize_t ti = group->basePackage->typeStrings.indexOfString(type, typeLen);
2390        if (ti < 0) {
2391            TABLE_NOISY(printf("Type not found in package %s\n", String8(group->name).string()));
2392            continue;
2393        }
2394
2395        const ssize_t ei = group->basePackage->keyStrings.indexOfString(name, nameLen);
2396        if (ei < 0) {
2397            TABLE_NOISY(printf("Name not found in package %s\n", String8(group->name).string()));
2398            continue;
2399        }
2400
2401        TABLE_NOISY(printf("Search indices: type=%d, name=%d\n", ti, ei));
2402
2403        const Type* const typeConfigs = group->packages[0]->getType(ti);
2404        if (typeConfigs == NULL || typeConfigs->configs.size() <= 0) {
2405            TABLE_NOISY(printf("Expected type structure not found in package %s for idnex %d\n",
2406                               String8(group->name).string(), ti));
2407        }
2408
2409        size_t NTC = typeConfigs->configs.size();
2410        for (size_t tci=0; tci<NTC; tci++) {
2411            const ResTable_type* const ty = typeConfigs->configs[tci];
2412            const uint32_t typeOffset = dtohl(ty->entriesStart);
2413
2414            const uint8_t* const end = ((const uint8_t*)ty) + dtohl(ty->header.size);
2415            const uint32_t* const eindex = (const uint32_t*)
2416                (((const uint8_t*)ty) + dtohs(ty->header.headerSize));
2417
2418            const size_t NE = dtohl(ty->entryCount);
2419            for (size_t i=0; i<NE; i++) {
2420                uint32_t offset = dtohl(eindex[i]);
2421                if (offset == ResTable_type::NO_ENTRY) {
2422                    continue;
2423                }
2424
2425                offset += typeOffset;
2426
2427                if (offset > (dtohl(ty->header.size)-sizeof(ResTable_entry))) {
2428                    LOGW("ResTable_entry at %d is beyond type chunk data %d",
2429                         offset, dtohl(ty->header.size));
2430                    return 0;
2431                }
2432                if ((offset&0x3) != 0) {
2433                    LOGW("ResTable_entry at %d (pkg=%d type=%d ent=%d) is not on an integer boundary when looking for %s:%s/%s",
2434                         (int)offset, (int)group->id, (int)ti+1, (int)i,
2435                         String8(package, packageLen).string(),
2436                         String8(type, typeLen).string(),
2437                         String8(name, nameLen).string());
2438                    return 0;
2439                }
2440
2441                const ResTable_entry* const entry = (const ResTable_entry*)
2442                    (((const uint8_t*)ty) + offset);
2443                if (dtohs(entry->size) < sizeof(*entry)) {
2444                    LOGW("ResTable_entry size %d is too small", dtohs(entry->size));
2445                    return BAD_TYPE;
2446                }
2447
2448                TABLE_SUPER_NOISY(printf("Looking at entry #%d: want str %d, have %d\n",
2449                                         i, ei, dtohl(entry->key.index)));
2450                if (dtohl(entry->key.index) == (size_t)ei) {
2451                    if (outTypeSpecFlags) {
2452                        *outTypeSpecFlags = typeConfigs->typeSpecFlags[i];
2453                    }
2454                    return Res_MAKEID(group->id-1, ti, i);
2455                }
2456            }
2457        }
2458    }
2459
2460    return 0;
2461}
2462
2463bool ResTable::expandResourceRef(const uint16_t* refStr, size_t refLen,
2464                                 String16* outPackage,
2465                                 String16* outType,
2466                                 String16* outName,
2467                                 const String16* defType,
2468                                 const String16* defPackage,
2469                                 const char** outErrorMsg)
2470{
2471    const char16_t* packageEnd = NULL;
2472    const char16_t* typeEnd = NULL;
2473    const char16_t* p = refStr;
2474    const char16_t* const end = p + refLen;
2475    while (p < end) {
2476        if (*p == ':') packageEnd = p;
2477        else if (*p == '/') {
2478            typeEnd = p;
2479            break;
2480        }
2481        p++;
2482    }
2483    p = refStr;
2484    if (*p == '@') p++;
2485
2486    if (packageEnd) {
2487        *outPackage = String16(p, packageEnd-p);
2488        p = packageEnd+1;
2489    } else {
2490        if (!defPackage) {
2491            if (outErrorMsg) {
2492                *outErrorMsg = "No resource package specified";
2493            }
2494            return false;
2495        }
2496        *outPackage = *defPackage;
2497    }
2498    if (typeEnd) {
2499        *outType = String16(p, typeEnd-p);
2500        p = typeEnd+1;
2501    } else {
2502        if (!defType) {
2503            if (outErrorMsg) {
2504                *outErrorMsg = "No resource type specified";
2505            }
2506            return false;
2507        }
2508        *outType = *defType;
2509    }
2510    *outName = String16(p, end-p);
2511    return true;
2512}
2513
2514static uint32_t get_hex(char c, bool* outError)
2515{
2516    if (c >= '0' && c <= '9') {
2517        return c - '0';
2518    } else if (c >= 'a' && c <= 'f') {
2519        return c - 'a' + 0xa;
2520    } else if (c >= 'A' && c <= 'F') {
2521        return c - 'A' + 0xa;
2522    }
2523    *outError = true;
2524    return 0;
2525}
2526
2527struct unit_entry
2528{
2529    const char* name;
2530    size_t len;
2531    uint8_t type;
2532    uint32_t unit;
2533    float scale;
2534};
2535
2536static const unit_entry unitNames[] = {
2537    { "px", strlen("px"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_PX, 1.0f },
2538    { "dip", strlen("dip"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_DIP, 1.0f },
2539    { "dp", strlen("dp"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_DIP, 1.0f },
2540    { "sp", strlen("sp"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_SP, 1.0f },
2541    { "pt", strlen("pt"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_PT, 1.0f },
2542    { "in", strlen("in"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_IN, 1.0f },
2543    { "mm", strlen("mm"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_MM, 1.0f },
2544    { "%", strlen("%"), Res_value::TYPE_FRACTION, Res_value::COMPLEX_UNIT_FRACTION, 1.0f/100 },
2545    { "%p", strlen("%p"), Res_value::TYPE_FRACTION, Res_value::COMPLEX_UNIT_FRACTION_PARENT, 1.0f/100 },
2546    { NULL, 0, 0, 0, 0 }
2547};
2548
2549static bool parse_unit(const char* str, Res_value* outValue,
2550                       float* outScale, const char** outEnd)
2551{
2552    const char* end = str;
2553    while (*end != 0 && !isspace((unsigned char)*end)) {
2554        end++;
2555    }
2556    const size_t len = end-str;
2557
2558    const char* realEnd = end;
2559    while (*realEnd != 0 && isspace((unsigned char)*realEnd)) {
2560        realEnd++;
2561    }
2562    if (*realEnd != 0) {
2563        return false;
2564    }
2565
2566    const unit_entry* cur = unitNames;
2567    while (cur->name) {
2568        if (len == cur->len && strncmp(cur->name, str, len) == 0) {
2569            outValue->dataType = cur->type;
2570            outValue->data = cur->unit << Res_value::COMPLEX_UNIT_SHIFT;
2571            *outScale = cur->scale;
2572            *outEnd = end;
2573            //printf("Found unit %s for %s\n", cur->name, str);
2574            return true;
2575        }
2576        cur++;
2577    }
2578
2579    return false;
2580}
2581
2582
2583bool ResTable::stringToInt(const char16_t* s, size_t len, Res_value* outValue)
2584{
2585    while (len > 0 && isspace16(*s)) {
2586        s++;
2587        len--;
2588    }
2589
2590    if (len <= 0) {
2591        return false;
2592    }
2593
2594    size_t i = 0;
2595    int32_t val = 0;
2596    bool neg = false;
2597
2598    if (*s == '-') {
2599        neg = true;
2600        i++;
2601    }
2602
2603    if (s[i] < '0' || s[i] > '9') {
2604        return false;
2605    }
2606
2607    // Decimal or hex?
2608    if (s[i] == '0' && s[i+1] == 'x') {
2609        if (outValue)
2610            outValue->dataType = outValue->TYPE_INT_HEX;
2611        i += 2;
2612        bool error = false;
2613        while (i < len && !error) {
2614            val = (val*16) + get_hex(s[i], &error);
2615            i++;
2616        }
2617        if (error) {
2618            return false;
2619        }
2620    } else {
2621        if (outValue)
2622            outValue->dataType = outValue->TYPE_INT_DEC;
2623        while (i < len) {
2624            if (s[i] < '0' || s[i] > '9') {
2625                return false;
2626            }
2627            val = (val*10) + s[i]-'0';
2628            i++;
2629        }
2630    }
2631
2632    if (neg) val = -val;
2633
2634    while (i < len && isspace16(s[i])) {
2635        i++;
2636    }
2637
2638    if (i == len) {
2639        if (outValue)
2640            outValue->data = val;
2641        return true;
2642    }
2643
2644    return false;
2645}
2646
2647bool ResTable::stringToFloat(const char16_t* s, size_t len, Res_value* outValue)
2648{
2649    while (len > 0 && isspace16(*s)) {
2650        s++;
2651        len--;
2652    }
2653
2654    if (len <= 0) {
2655        return false;
2656    }
2657
2658    char buf[128];
2659    int i=0;
2660    while (len > 0 && *s != 0 && i < 126) {
2661        if (*s > 255) {
2662            return false;
2663        }
2664        buf[i++] = *s++;
2665        len--;
2666    }
2667
2668    if (len > 0) {
2669        return false;
2670    }
2671    if (buf[0] < '0' && buf[0] > '9' && buf[0] != '.') {
2672        return false;
2673    }
2674
2675    buf[i] = 0;
2676    const char* end;
2677    float f = strtof(buf, (char**)&end);
2678
2679    if (*end != 0 && !isspace((unsigned char)*end)) {
2680        // Might be a unit...
2681        float scale;
2682        if (parse_unit(end, outValue, &scale, &end)) {
2683            f *= scale;
2684            const bool neg = f < 0;
2685            if (neg) f = -f;
2686            uint64_t bits = (uint64_t)(f*(1<<23)+.5f);
2687            uint32_t radix;
2688            uint32_t shift;
2689            if ((bits&0x7fffff) == 0) {
2690                // Always use 23p0 if there is no fraction, just to make
2691                // things easier to read.
2692                radix = Res_value::COMPLEX_RADIX_23p0;
2693                shift = 23;
2694            } else if ((bits&0xffffffffff800000LL) == 0) {
2695                // Magnitude is zero -- can fit in 0 bits of precision.
2696                radix = Res_value::COMPLEX_RADIX_0p23;
2697                shift = 0;
2698            } else if ((bits&0xffffffff80000000LL) == 0) {
2699                // Magnitude can fit in 8 bits of precision.
2700                radix = Res_value::COMPLEX_RADIX_8p15;
2701                shift = 8;
2702            } else if ((bits&0xffffff8000000000LL) == 0) {
2703                // Magnitude can fit in 16 bits of precision.
2704                radix = Res_value::COMPLEX_RADIX_16p7;
2705                shift = 16;
2706            } else {
2707                // Magnitude needs entire range, so no fractional part.
2708                radix = Res_value::COMPLEX_RADIX_23p0;
2709                shift = 23;
2710            }
2711            int32_t mantissa = (int32_t)(
2712                (bits>>shift) & Res_value::COMPLEX_MANTISSA_MASK);
2713            if (neg) {
2714                mantissa = (-mantissa) & Res_value::COMPLEX_MANTISSA_MASK;
2715            }
2716            outValue->data |=
2717                (radix<<Res_value::COMPLEX_RADIX_SHIFT)
2718                | (mantissa<<Res_value::COMPLEX_MANTISSA_SHIFT);
2719            //printf("Input value: %f 0x%016Lx, mult: %f, radix: %d, shift: %d, final: 0x%08x\n",
2720            //       f * (neg ? -1 : 1), bits, f*(1<<23),
2721            //       radix, shift, outValue->data);
2722            return true;
2723        }
2724        return false;
2725    }
2726
2727    while (*end != 0 && isspace((unsigned char)*end)) {
2728        end++;
2729    }
2730
2731    if (*end == 0) {
2732        if (outValue) {
2733            outValue->dataType = outValue->TYPE_FLOAT;
2734            *(float*)(&outValue->data) = f;
2735            return true;
2736        }
2737    }
2738
2739    return false;
2740}
2741
2742bool ResTable::stringToValue(Res_value* outValue, String16* outString,
2743                             const char16_t* s, size_t len,
2744                             bool preserveSpaces, bool coerceType,
2745                             uint32_t attrID,
2746                             const String16* defType,
2747                             const String16* defPackage,
2748                             Accessor* accessor,
2749                             void* accessorCookie,
2750                             uint32_t attrType,
2751                             bool enforcePrivate) const
2752{
2753    bool localizationSetting = accessor != NULL && accessor->getLocalizationSetting();
2754    const char* errorMsg = NULL;
2755
2756    outValue->size = sizeof(Res_value);
2757    outValue->res0 = 0;
2758
2759    // First strip leading/trailing whitespace.  Do this before handling
2760    // escapes, so they can be used to force whitespace into the string.
2761    if (!preserveSpaces) {
2762        while (len > 0 && isspace16(*s)) {
2763            s++;
2764            len--;
2765        }
2766        while (len > 0 && isspace16(s[len-1])) {
2767            len--;
2768        }
2769        // If the string ends with '\', then we keep the space after it.
2770        if (len > 0 && s[len-1] == '\\' && s[len] != 0) {
2771            len++;
2772        }
2773    }
2774
2775    //printf("Value for: %s\n", String8(s, len).string());
2776
2777    uint32_t l10nReq = ResTable_map::L10N_NOT_REQUIRED;
2778    uint32_t attrMin = 0x80000000, attrMax = 0x7fffffff;
2779    bool fromAccessor = false;
2780    if (attrID != 0 && !Res_INTERNALID(attrID)) {
2781        const ssize_t p = getResourcePackageIndex(attrID);
2782        const bag_entry* bag;
2783        ssize_t cnt = p >= 0 ? lockBag(attrID, &bag) : -1;
2784        //printf("For attr 0x%08x got bag of %d\n", attrID, cnt);
2785        if (cnt >= 0) {
2786            while (cnt > 0) {
2787                //printf("Entry 0x%08x = 0x%08x\n", bag->map.name.ident, bag->map.value.data);
2788                switch (bag->map.name.ident) {
2789                case ResTable_map::ATTR_TYPE:
2790                    attrType = bag->map.value.data;
2791                    break;
2792                case ResTable_map::ATTR_MIN:
2793                    attrMin = bag->map.value.data;
2794                    break;
2795                case ResTable_map::ATTR_MAX:
2796                    attrMax = bag->map.value.data;
2797                    break;
2798                case ResTable_map::ATTR_L10N:
2799                    l10nReq = bag->map.value.data;
2800                    break;
2801                }
2802                bag++;
2803                cnt--;
2804            }
2805            unlockBag(bag);
2806        } else if (accessor && accessor->getAttributeType(attrID, &attrType)) {
2807            fromAccessor = true;
2808            if (attrType == ResTable_map::TYPE_ENUM
2809                    || attrType == ResTable_map::TYPE_FLAGS
2810                    || attrType == ResTable_map::TYPE_INTEGER) {
2811                accessor->getAttributeMin(attrID, &attrMin);
2812                accessor->getAttributeMax(attrID, &attrMax);
2813            }
2814            if (localizationSetting) {
2815                l10nReq = accessor->getAttributeL10N(attrID);
2816            }
2817        }
2818    }
2819
2820    const bool canStringCoerce =
2821        coerceType && (attrType&ResTable_map::TYPE_STRING) != 0;
2822
2823    if (*s == '@') {
2824        outValue->dataType = outValue->TYPE_REFERENCE;
2825
2826        // Note: we don't check attrType here because the reference can
2827        // be to any other type; we just need to count on the client making
2828        // sure the referenced type is correct.
2829
2830        //printf("Looking up ref: %s\n", String8(s, len).string());
2831
2832        // It's a reference!
2833        if (len == 5 && s[1]=='n' && s[2]=='u' && s[3]=='l' && s[4]=='l') {
2834            outValue->data = 0;
2835            return true;
2836        } else {
2837            bool createIfNotFound = false;
2838            const char16_t* resourceRefName;
2839            int resourceNameLen;
2840            if (len > 2 && s[1] == '+') {
2841                createIfNotFound = true;
2842                resourceRefName = s + 2;
2843                resourceNameLen = len - 2;
2844            } else if (len > 2 && s[1] == '*') {
2845                enforcePrivate = false;
2846                resourceRefName = s + 2;
2847                resourceNameLen = len - 2;
2848            } else {
2849                createIfNotFound = false;
2850                resourceRefName = s + 1;
2851                resourceNameLen = len - 1;
2852            }
2853            String16 package, type, name;
2854            if (!expandResourceRef(resourceRefName,resourceNameLen, &package, &type, &name,
2855                                   defType, defPackage, &errorMsg)) {
2856                if (accessor != NULL) {
2857                    accessor->reportError(accessorCookie, errorMsg);
2858                }
2859                return false;
2860            }
2861
2862            uint32_t specFlags = 0;
2863            uint32_t rid = identifierForName(name.string(), name.size(), type.string(),
2864                    type.size(), package.string(), package.size(), &specFlags);
2865            if (rid != 0) {
2866                if (enforcePrivate) {
2867                    if ((specFlags&ResTable_typeSpec::SPEC_PUBLIC) == 0) {
2868                        if (accessor != NULL) {
2869                            accessor->reportError(accessorCookie, "Resource is not public.");
2870                        }
2871                        return false;
2872                    }
2873                }
2874                if (!accessor) {
2875                    outValue->data = rid;
2876                    return true;
2877                }
2878                rid = Res_MAKEID(
2879                    accessor->getRemappedPackage(Res_GETPACKAGE(rid)),
2880                    Res_GETTYPE(rid), Res_GETENTRY(rid));
2881                TABLE_NOISY(printf("Incl %s:%s/%s: 0x%08x\n",
2882                       String8(package).string(), String8(type).string(),
2883                       String8(name).string(), rid));
2884                outValue->data = rid;
2885                return true;
2886            }
2887
2888            if (accessor) {
2889                uint32_t rid = accessor->getCustomResourceWithCreation(package, type, name,
2890                                                                       createIfNotFound);
2891                if (rid != 0) {
2892                    TABLE_NOISY(printf("Pckg %s:%s/%s: 0x%08x\n",
2893                           String8(package).string(), String8(type).string(),
2894                           String8(name).string(), rid));
2895                    outValue->data = rid;
2896                    return true;
2897                }
2898            }
2899        }
2900
2901        if (accessor != NULL) {
2902            accessor->reportError(accessorCookie, "No resource found that matches the given name");
2903        }
2904        return false;
2905    }
2906
2907    // if we got to here, and localization is required and it's not a reference,
2908    // complain and bail.
2909    if (l10nReq == ResTable_map::L10N_SUGGESTED) {
2910        if (localizationSetting) {
2911            if (accessor != NULL) {
2912                accessor->reportError(accessorCookie, "This attribute must be localized.");
2913            }
2914        }
2915    }
2916
2917    if (*s == '#') {
2918        // It's a color!  Convert to an integer of the form 0xaarrggbb.
2919        uint32_t color = 0;
2920        bool error = false;
2921        if (len == 4) {
2922            outValue->dataType = outValue->TYPE_INT_COLOR_RGB4;
2923            color |= 0xFF000000;
2924            color |= get_hex(s[1], &error) << 20;
2925            color |= get_hex(s[1], &error) << 16;
2926            color |= get_hex(s[2], &error) << 12;
2927            color |= get_hex(s[2], &error) << 8;
2928            color |= get_hex(s[3], &error) << 4;
2929            color |= get_hex(s[3], &error);
2930        } else if (len == 5) {
2931            outValue->dataType = outValue->TYPE_INT_COLOR_ARGB4;
2932            color |= get_hex(s[1], &error) << 28;
2933            color |= get_hex(s[1], &error) << 24;
2934            color |= get_hex(s[2], &error) << 20;
2935            color |= get_hex(s[2], &error) << 16;
2936            color |= get_hex(s[3], &error) << 12;
2937            color |= get_hex(s[3], &error) << 8;
2938            color |= get_hex(s[4], &error) << 4;
2939            color |= get_hex(s[4], &error);
2940        } else if (len == 7) {
2941            outValue->dataType = outValue->TYPE_INT_COLOR_RGB8;
2942            color |= 0xFF000000;
2943            color |= get_hex(s[1], &error) << 20;
2944            color |= get_hex(s[2], &error) << 16;
2945            color |= get_hex(s[3], &error) << 12;
2946            color |= get_hex(s[4], &error) << 8;
2947            color |= get_hex(s[5], &error) << 4;
2948            color |= get_hex(s[6], &error);
2949        } else if (len == 9) {
2950            outValue->dataType = outValue->TYPE_INT_COLOR_ARGB8;
2951            color |= get_hex(s[1], &error) << 28;
2952            color |= get_hex(s[2], &error) << 24;
2953            color |= get_hex(s[3], &error) << 20;
2954            color |= get_hex(s[4], &error) << 16;
2955            color |= get_hex(s[5], &error) << 12;
2956            color |= get_hex(s[6], &error) << 8;
2957            color |= get_hex(s[7], &error) << 4;
2958            color |= get_hex(s[8], &error);
2959        } else {
2960            error = true;
2961        }
2962        if (!error) {
2963            if ((attrType&ResTable_map::TYPE_COLOR) == 0) {
2964                if (!canStringCoerce) {
2965                    if (accessor != NULL) {
2966                        accessor->reportError(accessorCookie,
2967                                "Color types not allowed");
2968                    }
2969                    return false;
2970                }
2971            } else {
2972                outValue->data = color;
2973                //printf("Color input=%s, output=0x%x\n", String8(s, len).string(), color);
2974                return true;
2975            }
2976        } else {
2977            if ((attrType&ResTable_map::TYPE_COLOR) != 0) {
2978                if (accessor != NULL) {
2979                    accessor->reportError(accessorCookie, "Color value not valid --"
2980                            " must be #rgb, #argb, #rrggbb, or #aarrggbb");
2981                }
2982                #if 0
2983                fprintf(stderr, "%s: Color ID %s value %s is not valid\n",
2984                        "Resource File", //(const char*)in->getPrintableSource(),
2985                        String8(*curTag).string(),
2986                        String8(s, len).string());
2987                #endif
2988                return false;
2989            }
2990        }
2991    }
2992
2993    if (*s == '?') {
2994        outValue->dataType = outValue->TYPE_ATTRIBUTE;
2995
2996        // Note: we don't check attrType here because the reference can
2997        // be to any other type; we just need to count on the client making
2998        // sure the referenced type is correct.
2999
3000        //printf("Looking up attr: %s\n", String8(s, len).string());
3001
3002        static const String16 attr16("attr");
3003        String16 package, type, name;
3004        if (!expandResourceRef(s+1, len-1, &package, &type, &name,
3005                               &attr16, defPackage, &errorMsg)) {
3006            if (accessor != NULL) {
3007                accessor->reportError(accessorCookie, errorMsg);
3008            }
3009            return false;
3010        }
3011
3012        //printf("Pkg: %s, Type: %s, Name: %s\n",
3013        //       String8(package).string(), String8(type).string(),
3014        //       String8(name).string());
3015        uint32_t specFlags = 0;
3016        uint32_t rid =
3017            identifierForName(name.string(), name.size(),
3018                              type.string(), type.size(),
3019                              package.string(), package.size(), &specFlags);
3020        if (rid != 0) {
3021            if (enforcePrivate) {
3022                if ((specFlags&ResTable_typeSpec::SPEC_PUBLIC) == 0) {
3023                    if (accessor != NULL) {
3024                        accessor->reportError(accessorCookie, "Attribute is not public.");
3025                    }
3026                    return false;
3027                }
3028            }
3029            if (!accessor) {
3030                outValue->data = rid;
3031                return true;
3032            }
3033            rid = Res_MAKEID(
3034                accessor->getRemappedPackage(Res_GETPACKAGE(rid)),
3035                Res_GETTYPE(rid), Res_GETENTRY(rid));
3036            //printf("Incl %s:%s/%s: 0x%08x\n",
3037            //       String8(package).string(), String8(type).string(),
3038            //       String8(name).string(), rid);
3039            outValue->data = rid;
3040            return true;
3041        }
3042
3043        if (accessor) {
3044            uint32_t rid = accessor->getCustomResource(package, type, name);
3045            if (rid != 0) {
3046                //printf("Mine %s:%s/%s: 0x%08x\n",
3047                //       String8(package).string(), String8(type).string(),
3048                //       String8(name).string(), rid);
3049                outValue->data = rid;
3050                return true;
3051            }
3052        }
3053
3054        if (accessor != NULL) {
3055            accessor->reportError(accessorCookie, "No resource found that matches the given name");
3056        }
3057        return false;
3058    }
3059
3060    if (stringToInt(s, len, outValue)) {
3061        if ((attrType&ResTable_map::TYPE_INTEGER) == 0) {
3062            // If this type does not allow integers, but does allow floats,
3063            // fall through on this error case because the float type should
3064            // be able to accept any integer value.
3065            if (!canStringCoerce && (attrType&ResTable_map::TYPE_FLOAT) == 0) {
3066                if (accessor != NULL) {
3067                    accessor->reportError(accessorCookie, "Integer types not allowed");
3068                }
3069                return false;
3070            }
3071        } else {
3072            if (((int32_t)outValue->data) < ((int32_t)attrMin)
3073                    || ((int32_t)outValue->data) > ((int32_t)attrMax)) {
3074                if (accessor != NULL) {
3075                    accessor->reportError(accessorCookie, "Integer value out of range");
3076                }
3077                return false;
3078            }
3079            return true;
3080        }
3081    }
3082
3083    if (stringToFloat(s, len, outValue)) {
3084        if (outValue->dataType == Res_value::TYPE_DIMENSION) {
3085            if ((attrType&ResTable_map::TYPE_DIMENSION) != 0) {
3086                return true;
3087            }
3088            if (!canStringCoerce) {
3089                if (accessor != NULL) {
3090                    accessor->reportError(accessorCookie, "Dimension types not allowed");
3091                }
3092                return false;
3093            }
3094        } else if (outValue->dataType == Res_value::TYPE_FRACTION) {
3095            if ((attrType&ResTable_map::TYPE_FRACTION) != 0) {
3096                return true;
3097            }
3098            if (!canStringCoerce) {
3099                if (accessor != NULL) {
3100                    accessor->reportError(accessorCookie, "Fraction types not allowed");
3101                }
3102                return false;
3103            }
3104        } else if ((attrType&ResTable_map::TYPE_FLOAT) == 0) {
3105            if (!canStringCoerce) {
3106                if (accessor != NULL) {
3107                    accessor->reportError(accessorCookie, "Float types not allowed");
3108                }
3109                return false;
3110            }
3111        } else {
3112            return true;
3113        }
3114    }
3115
3116    if (len == 4) {
3117        if ((s[0] == 't' || s[0] == 'T') &&
3118            (s[1] == 'r' || s[1] == 'R') &&
3119            (s[2] == 'u' || s[2] == 'U') &&
3120            (s[3] == 'e' || s[3] == 'E')) {
3121            if ((attrType&ResTable_map::TYPE_BOOLEAN) == 0) {
3122                if (!canStringCoerce) {
3123                    if (accessor != NULL) {
3124                        accessor->reportError(accessorCookie, "Boolean types not allowed");
3125                    }
3126                    return false;
3127                }
3128            } else {
3129                outValue->dataType = outValue->TYPE_INT_BOOLEAN;
3130                outValue->data = (uint32_t)-1;
3131                return true;
3132            }
3133        }
3134    }
3135
3136    if (len == 5) {
3137        if ((s[0] == 'f' || s[0] == 'F') &&
3138            (s[1] == 'a' || s[1] == 'A') &&
3139            (s[2] == 'l' || s[2] == 'L') &&
3140            (s[3] == 's' || s[3] == 'S') &&
3141            (s[4] == 'e' || s[4] == 'E')) {
3142            if ((attrType&ResTable_map::TYPE_BOOLEAN) == 0) {
3143                if (!canStringCoerce) {
3144                    if (accessor != NULL) {
3145                        accessor->reportError(accessorCookie, "Boolean types not allowed");
3146                    }
3147                    return false;
3148                }
3149            } else {
3150                outValue->dataType = outValue->TYPE_INT_BOOLEAN;
3151                outValue->data = 0;
3152                return true;
3153            }
3154        }
3155    }
3156
3157    if ((attrType&ResTable_map::TYPE_ENUM) != 0) {
3158        const ssize_t p = getResourcePackageIndex(attrID);
3159        const bag_entry* bag;
3160        ssize_t cnt = p >= 0 ? lockBag(attrID, &bag) : -1;
3161        //printf("Got %d for enum\n", cnt);
3162        if (cnt >= 0) {
3163            resource_name rname;
3164            while (cnt > 0) {
3165                if (!Res_INTERNALID(bag->map.name.ident)) {
3166                    //printf("Trying attr #%08x\n", bag->map.name.ident);
3167                    if (getResourceName(bag->map.name.ident, &rname)) {
3168                        #if 0
3169                        printf("Matching %s against %s (0x%08x)\n",
3170                               String8(s, len).string(),
3171                               String8(rname.name, rname.nameLen).string(),
3172                               bag->map.name.ident);
3173                        #endif
3174                        if (strzcmp16(s, len, rname.name, rname.nameLen) == 0) {
3175                            outValue->dataType = bag->map.value.dataType;
3176                            outValue->data = bag->map.value.data;
3177                            unlockBag(bag);
3178                            return true;
3179                        }
3180                    }
3181
3182                }
3183                bag++;
3184                cnt--;
3185            }
3186            unlockBag(bag);
3187        }
3188
3189        if (fromAccessor) {
3190            if (accessor->getAttributeEnum(attrID, s, len, outValue)) {
3191                return true;
3192            }
3193        }
3194    }
3195
3196    if ((attrType&ResTable_map::TYPE_FLAGS) != 0) {
3197        const ssize_t p = getResourcePackageIndex(attrID);
3198        const bag_entry* bag;
3199        ssize_t cnt = p >= 0 ? lockBag(attrID, &bag) : -1;
3200        //printf("Got %d for flags\n", cnt);
3201        if (cnt >= 0) {
3202            bool failed = false;
3203            resource_name rname;
3204            outValue->dataType = Res_value::TYPE_INT_HEX;
3205            outValue->data = 0;
3206            const char16_t* end = s + len;
3207            const char16_t* pos = s;
3208            while (pos < end && !failed) {
3209                const char16_t* start = pos;
3210                pos++;
3211                while (pos < end && *pos != '|') {
3212                    pos++;
3213                }
3214                //printf("Looking for: %s\n", String8(start, pos-start).string());
3215                const bag_entry* bagi = bag;
3216                ssize_t i;
3217                for (i=0; i<cnt; i++, bagi++) {
3218                    if (!Res_INTERNALID(bagi->map.name.ident)) {
3219                        //printf("Trying attr #%08x\n", bagi->map.name.ident);
3220                        if (getResourceName(bagi->map.name.ident, &rname)) {
3221                            #if 0
3222                            printf("Matching %s against %s (0x%08x)\n",
3223                                   String8(start,pos-start).string(),
3224                                   String8(rname.name, rname.nameLen).string(),
3225                                   bagi->map.name.ident);
3226                            #endif
3227                            if (strzcmp16(start, pos-start, rname.name, rname.nameLen) == 0) {
3228                                outValue->data |= bagi->map.value.data;
3229                                break;
3230                            }
3231                        }
3232                    }
3233                }
3234                if (i >= cnt) {
3235                    // Didn't find this flag identifier.
3236                    failed = true;
3237                }
3238                if (pos < end) {
3239                    pos++;
3240                }
3241            }
3242            unlockBag(bag);
3243            if (!failed) {
3244                //printf("Final flag value: 0x%lx\n", outValue->data);
3245                return true;
3246            }
3247        }
3248
3249
3250        if (fromAccessor) {
3251            if (accessor->getAttributeFlags(attrID, s, len, outValue)) {
3252                //printf("Final flag value: 0x%lx\n", outValue->data);
3253                return true;
3254            }
3255        }
3256    }
3257
3258    if ((attrType&ResTable_map::TYPE_STRING) == 0) {
3259        if (accessor != NULL) {
3260            accessor->reportError(accessorCookie, "String types not allowed");
3261        }
3262        return false;
3263    }
3264
3265    // Generic string handling...
3266    outValue->dataType = outValue->TYPE_STRING;
3267    if (outString) {
3268        bool failed = collectString(outString, s, len, preserveSpaces, &errorMsg);
3269        if (accessor != NULL) {
3270            accessor->reportError(accessorCookie, errorMsg);
3271        }
3272        return failed;
3273    }
3274
3275    return true;
3276}
3277
3278bool ResTable::collectString(String16* outString,
3279                             const char16_t* s, size_t len,
3280                             bool preserveSpaces,
3281                             const char** outErrorMsg,
3282                             bool append)
3283{
3284    String16 tmp;
3285
3286    char quoted = 0;
3287    const char16_t* p = s;
3288    while (p < (s+len)) {
3289        while (p < (s+len)) {
3290            const char16_t c = *p;
3291            if (c == '\\') {
3292                break;
3293            }
3294            if (!preserveSpaces) {
3295                if (quoted == 0 && isspace16(c)
3296                    && (c != ' ' || isspace16(*(p+1)))) {
3297                    break;
3298                }
3299                if (c == '"' && (quoted == 0 || quoted == '"')) {
3300                    break;
3301                }
3302                if (c == '\'' && (quoted == 0 || quoted == '\'')) {
3303                    /*
3304                     * In practice, when people write ' instead of \'
3305                     * in a string, they are doing it by accident
3306                     * instead of really meaning to use ' as a quoting
3307                     * character.  Warn them so they don't lose it.
3308                     */
3309                    if (outErrorMsg) {
3310                        *outErrorMsg = "Apostrophe not preceded by \\";
3311                    }
3312                    return false;
3313                }
3314            }
3315            p++;
3316        }
3317        if (p < (s+len)) {
3318            if (p > s) {
3319                tmp.append(String16(s, p-s));
3320            }
3321            if (!preserveSpaces && (*p == '"' || *p == '\'')) {
3322                if (quoted == 0) {
3323                    quoted = *p;
3324                } else {
3325                    quoted = 0;
3326                }
3327                p++;
3328            } else if (!preserveSpaces && isspace16(*p)) {
3329                // Space outside of a quote -- consume all spaces and
3330                // leave a single plain space char.
3331                tmp.append(String16(" "));
3332                p++;
3333                while (p < (s+len) && isspace16(*p)) {
3334                    p++;
3335                }
3336            } else if (*p == '\\') {
3337                p++;
3338                if (p < (s+len)) {
3339                    switch (*p) {
3340                    case 't':
3341                        tmp.append(String16("\t"));
3342                        break;
3343                    case 'n':
3344                        tmp.append(String16("\n"));
3345                        break;
3346                    case '#':
3347                        tmp.append(String16("#"));
3348                        break;
3349                    case '@':
3350                        tmp.append(String16("@"));
3351                        break;
3352                    case '?':
3353                        tmp.append(String16("?"));
3354                        break;
3355                    case '"':
3356                        tmp.append(String16("\""));
3357                        break;
3358                    case '\'':
3359                        tmp.append(String16("'"));
3360                        break;
3361                    case '\\':
3362                        tmp.append(String16("\\"));
3363                        break;
3364                    case 'u':
3365                    {
3366                        char16_t chr = 0;
3367                        int i = 0;
3368                        while (i < 4 && p[1] != 0) {
3369                            p++;
3370                            i++;
3371                            int c;
3372                            if (*p >= '0' && *p <= '9') {
3373                                c = *p - '0';
3374                            } else if (*p >= 'a' && *p <= 'f') {
3375                                c = *p - 'a' + 10;
3376                            } else if (*p >= 'A' && *p <= 'F') {
3377                                c = *p - 'A' + 10;
3378                            } else {
3379                                if (outErrorMsg) {
3380                                    *outErrorMsg = "Bad character in \\u unicode escape sequence";
3381                                }
3382                                return false;
3383                            }
3384                            chr = (chr<<4) | c;
3385                        }
3386                        tmp.append(String16(&chr, 1));
3387                    } break;
3388                    default:
3389                        // ignore unknown escape chars.
3390                        break;
3391                    }
3392                    p++;
3393                }
3394            }
3395            len -= (p-s);
3396            s = p;
3397        }
3398    }
3399
3400    if (tmp.size() != 0) {
3401        if (len > 0) {
3402            tmp.append(String16(s, len));
3403        }
3404        if (append) {
3405            outString->append(tmp);
3406        } else {
3407            outString->setTo(tmp);
3408        }
3409    } else {
3410        if (append) {
3411            outString->append(String16(s, len));
3412        } else {
3413            outString->setTo(s, len);
3414        }
3415    }
3416
3417    return true;
3418}
3419
3420size_t ResTable::getBasePackageCount() const
3421{
3422    if (mError != NO_ERROR) {
3423        return 0;
3424    }
3425    return mPackageGroups.size();
3426}
3427
3428const char16_t* ResTable::getBasePackageName(size_t idx) const
3429{
3430    if (mError != NO_ERROR) {
3431        return 0;
3432    }
3433    LOG_FATAL_IF(idx >= mPackageGroups.size(),
3434                 "Requested package index %d past package count %d",
3435                 (int)idx, (int)mPackageGroups.size());
3436    return mPackageGroups[idx]->name.string();
3437}
3438
3439uint32_t ResTable::getBasePackageId(size_t idx) const
3440{
3441    if (mError != NO_ERROR) {
3442        return 0;
3443    }
3444    LOG_FATAL_IF(idx >= mPackageGroups.size(),
3445                 "Requested package index %d past package count %d",
3446                 (int)idx, (int)mPackageGroups.size());
3447    return mPackageGroups[idx]->id;
3448}
3449
3450size_t ResTable::getTableCount() const
3451{
3452    return mHeaders.size();
3453}
3454
3455const ResStringPool* ResTable::getTableStringBlock(size_t index) const
3456{
3457    return &mHeaders[index]->values;
3458}
3459
3460void* ResTable::getTableCookie(size_t index) const
3461{
3462    return mHeaders[index]->cookie;
3463}
3464
3465void ResTable::getConfigurations(Vector<ResTable_config>* configs) const
3466{
3467    const size_t I = mPackageGroups.size();
3468    for (size_t i=0; i<I; i++) {
3469        const PackageGroup* packageGroup = mPackageGroups[i];
3470        const size_t J = packageGroup->packages.size();
3471        for (size_t j=0; j<J; j++) {
3472            const Package* package = packageGroup->packages[j];
3473            const size_t K = package->types.size();
3474            for (size_t k=0; k<K; k++) {
3475                const Type* type = package->types[k];
3476                if (type == NULL) continue;
3477                const size_t L = type->configs.size();
3478                for (size_t l=0; l<L; l++) {
3479                    const ResTable_type* config = type->configs[l];
3480                    const ResTable_config* cfg = &config->config;
3481                    // only insert unique
3482                    const size_t M = configs->size();
3483                    size_t m;
3484                    for (m=0; m<M; m++) {
3485                        if (0 == (*configs)[m].compare(*cfg)) {
3486                            break;
3487                        }
3488                    }
3489                    // if we didn't find it
3490                    if (m == M) {
3491                        configs->add(*cfg);
3492                    }
3493                }
3494            }
3495        }
3496    }
3497}
3498
3499void ResTable::getLocales(Vector<String8>* locales) const
3500{
3501    Vector<ResTable_config> configs;
3502    LOGD("calling getConfigurations");
3503    getConfigurations(&configs);
3504    LOGD("called getConfigurations size=%d", (int)configs.size());
3505    const size_t I = configs.size();
3506    for (size_t i=0; i<I; i++) {
3507        char locale[6];
3508        configs[i].getLocale(locale);
3509        const size_t J = locales->size();
3510        size_t j;
3511        for (j=0; j<J; j++) {
3512            if (0 == strcmp(locale, (*locales)[j].string())) {
3513                break;
3514            }
3515        }
3516        if (j == J) {
3517            locales->add(String8(locale));
3518        }
3519    }
3520}
3521
3522ssize_t ResTable::getEntry(
3523    const Package* package, int typeIndex, int entryIndex,
3524    const ResTable_config* config,
3525    const ResTable_type** outType, const ResTable_entry** outEntry,
3526    const Type** outTypeClass) const
3527{
3528    LOGV("Getting entry from package %p\n", package);
3529    const ResTable_package* const pkg = package->package;
3530
3531    const Type* allTypes = package->getType(typeIndex);
3532    LOGV("allTypes=%p\n", allTypes);
3533    if (allTypes == NULL) {
3534        LOGV("Skipping entry type index 0x%02x because type is NULL!\n", typeIndex);
3535        return 0;
3536    }
3537
3538    if ((size_t)entryIndex >= allTypes->entryCount) {
3539        LOGW("getEntry failing because entryIndex %d is beyond type entryCount %d",
3540            entryIndex, (int)allTypes->entryCount);
3541        return BAD_TYPE;
3542    }
3543
3544    const ResTable_type* type = NULL;
3545    uint32_t offset = ResTable_type::NO_ENTRY;
3546    ResTable_config bestConfig;
3547    memset(&bestConfig, 0, sizeof(bestConfig)); // make the compiler shut up
3548
3549    const size_t NT = allTypes->configs.size();
3550    for (size_t i=0; i<NT; i++) {
3551        const ResTable_type* const thisType = allTypes->configs[i];
3552        if (thisType == NULL) continue;
3553
3554        ResTable_config thisConfig;
3555        thisConfig.copyFromDtoH(thisType->config);
3556
3557        TABLE_GETENTRY(LOGI("Match entry 0x%x in type 0x%x (sz 0x%x): imsi:%d/%d=%d/%d lang:%c%c=%c%c cnt:%c%c=%c%c "
3558                            "orien:%d=%d touch:%d=%d density:%d=%d key:%d=%d inp:%d=%d nav:%d=%d w:%d=%d h:%d=%d\n",
3559                           entryIndex, typeIndex+1, dtohl(thisType->config.size),
3560                           thisConfig.mcc, thisConfig.mnc,
3561                           config ? config->mcc : 0, config ? config->mnc : 0,
3562                           thisConfig.language[0] ? thisConfig.language[0] : '-',
3563                           thisConfig.language[1] ? thisConfig.language[1] : '-',
3564                           config && config->language[0] ? config->language[0] : '-',
3565                           config && config->language[1] ? config->language[1] : '-',
3566                           thisConfig.country[0] ? thisConfig.country[0] : '-',
3567                           thisConfig.country[1] ? thisConfig.country[1] : '-',
3568                           config && config->country[0] ? config->country[0] : '-',
3569                           config && config->country[1] ? config->country[1] : '-',
3570                           thisConfig.orientation,
3571                           config ? config->orientation : 0,
3572                           thisConfig.touchscreen,
3573                           config ? config->touchscreen : 0,
3574                           thisConfig.density,
3575                           config ? config->density : 0,
3576                           thisConfig.keyboard,
3577                           config ? config->keyboard : 0,
3578                           thisConfig.inputFlags,
3579                           config ? config->inputFlags : 0,
3580                           thisConfig.navigation,
3581                           config ? config->navigation : 0,
3582                           thisConfig.screenWidth,
3583                           config ? config->screenWidth : 0,
3584                           thisConfig.screenHeight,
3585                           config ? config->screenHeight : 0));
3586
3587        // Check to make sure this one is valid for the current parameters.
3588        if (config && !thisConfig.match(*config)) {
3589            TABLE_GETENTRY(LOGI("Does not match config!\n"));
3590            continue;
3591        }
3592
3593        // Check if there is the desired entry in this type.
3594
3595        const uint8_t* const end = ((const uint8_t*)thisType)
3596            + dtohl(thisType->header.size);
3597        const uint32_t* const eindex = (const uint32_t*)
3598            (((const uint8_t*)thisType) + dtohs(thisType->header.headerSize));
3599
3600        uint32_t thisOffset = dtohl(eindex[entryIndex]);
3601        if (thisOffset == ResTable_type::NO_ENTRY) {
3602            TABLE_GETENTRY(LOGI("Skipping because it is not defined!\n"));
3603            continue;
3604        }
3605
3606        if (type != NULL) {
3607            // Check if this one is less specific than the last found.  If so,
3608            // we will skip it.  We check starting with things we most care
3609            // about to those we least care about.
3610            if (!thisConfig.isBetterThan(bestConfig, config)) {
3611                TABLE_GETENTRY(LOGI("This config is worse than last!\n"));
3612                continue;
3613            }
3614        }
3615
3616        type = thisType;
3617        offset = thisOffset;
3618        bestConfig = thisConfig;
3619        TABLE_GETENTRY(LOGI("Best entry so far -- using it!\n"));
3620        if (!config) break;
3621    }
3622
3623    if (type == NULL) {
3624        TABLE_GETENTRY(LOGI("No value found for requested entry!\n"));
3625        return BAD_INDEX;
3626    }
3627
3628    offset += dtohl(type->entriesStart);
3629    TABLE_NOISY(aout << "Looking in resource table " << package->header->header
3630          << ", typeOff="
3631          << (void*)(((const char*)type)-((const char*)package->header->header))
3632          << ", offset=" << (void*)offset << endl);
3633
3634    if (offset > (dtohl(type->header.size)-sizeof(ResTable_entry))) {
3635        LOGW("ResTable_entry at 0x%x is beyond type chunk data 0x%x",
3636             offset, dtohl(type->header.size));
3637        return BAD_TYPE;
3638    }
3639    if ((offset&0x3) != 0) {
3640        LOGW("ResTable_entry at 0x%x is not on an integer boundary",
3641             offset);
3642        return BAD_TYPE;
3643    }
3644
3645    const ResTable_entry* const entry = (const ResTable_entry*)
3646        (((const uint8_t*)type) + offset);
3647    if (dtohs(entry->size) < sizeof(*entry)) {
3648        LOGW("ResTable_entry size 0x%x is too small", dtohs(entry->size));
3649        return BAD_TYPE;
3650    }
3651
3652    *outType = type;
3653    *outEntry = entry;
3654    if (outTypeClass != NULL) {
3655        *outTypeClass = allTypes;
3656    }
3657    return offset + dtohs(entry->size);
3658}
3659
3660status_t ResTable::parsePackage(const ResTable_package* const pkg,
3661                                const Header* const header)
3662{
3663    const uint8_t* base = (const uint8_t*)pkg;
3664    status_t err = validate_chunk(&pkg->header, sizeof(*pkg),
3665                                  header->dataEnd, "ResTable_package");
3666    if (err != NO_ERROR) {
3667        return (mError=err);
3668    }
3669
3670    const size_t pkgSize = dtohl(pkg->header.size);
3671
3672    if (dtohl(pkg->typeStrings) >= pkgSize) {
3673        LOGW("ResTable_package type strings at %p are past chunk size %p.",
3674             (void*)dtohl(pkg->typeStrings), (void*)pkgSize);
3675        return (mError=BAD_TYPE);
3676    }
3677    if ((dtohl(pkg->typeStrings)&0x3) != 0) {
3678        LOGW("ResTable_package type strings at %p is not on an integer boundary.",
3679             (void*)dtohl(pkg->typeStrings));
3680        return (mError=BAD_TYPE);
3681    }
3682    if (dtohl(pkg->keyStrings) >= pkgSize) {
3683        LOGW("ResTable_package key strings at %p are past chunk size %p.",
3684             (void*)dtohl(pkg->keyStrings), (void*)pkgSize);
3685        return (mError=BAD_TYPE);
3686    }
3687    if ((dtohl(pkg->keyStrings)&0x3) != 0) {
3688        LOGW("ResTable_package key strings at %p is not on an integer boundary.",
3689             (void*)dtohl(pkg->keyStrings));
3690        return (mError=BAD_TYPE);
3691    }
3692
3693    Package* package = NULL;
3694    PackageGroup* group = NULL;
3695    uint32_t id = dtohl(pkg->id);
3696    if (id != 0 && id < 256) {
3697
3698        package = new Package(this, header, pkg);
3699        if (package == NULL) {
3700            return (mError=NO_MEMORY);
3701        }
3702
3703        size_t idx = mPackageMap[id];
3704        if (idx == 0) {
3705            idx = mPackageGroups.size()+1;
3706
3707            char16_t tmpName[sizeof(pkg->name)/sizeof(char16_t)];
3708            strcpy16_dtoh(tmpName, pkg->name, sizeof(pkg->name)/sizeof(char16_t));
3709            group = new PackageGroup(this, String16(tmpName), id);
3710            if (group == NULL) {
3711                delete package;
3712                return (mError=NO_MEMORY);
3713            }
3714
3715            err = package->typeStrings.setTo(base+dtohl(pkg->typeStrings),
3716                                           header->dataEnd-(base+dtohl(pkg->typeStrings)));
3717            if (err != NO_ERROR) {
3718                delete group;
3719                delete package;
3720                return (mError=err);
3721            }
3722            err = package->keyStrings.setTo(base+dtohl(pkg->keyStrings),
3723                                          header->dataEnd-(base+dtohl(pkg->keyStrings)));
3724            if (err != NO_ERROR) {
3725                delete group;
3726                delete package;
3727                return (mError=err);
3728            }
3729
3730            //printf("Adding new package id %d at index %d\n", id, idx);
3731            err = mPackageGroups.add(group);
3732            if (err < NO_ERROR) {
3733                return (mError=err);
3734            }
3735            group->basePackage = package;
3736
3737            mPackageMap[id] = (uint8_t)idx;
3738        } else {
3739            group = mPackageGroups.itemAt(idx-1);
3740            if (group == NULL) {
3741                return (mError=UNKNOWN_ERROR);
3742            }
3743        }
3744        err = group->packages.add(package);
3745        if (err < NO_ERROR) {
3746            return (mError=err);
3747        }
3748    } else {
3749        LOG_ALWAYS_FATAL("Skins not supported!");
3750        return NO_ERROR;
3751    }
3752
3753
3754    // Iterate through all chunks.
3755    size_t curPackage = 0;
3756
3757    const ResChunk_header* chunk =
3758        (const ResChunk_header*)(((const uint8_t*)pkg)
3759                                 + dtohs(pkg->header.headerSize));
3760    const uint8_t* endPos = ((const uint8_t*)pkg) + dtohs(pkg->header.size);
3761    while (((const uint8_t*)chunk) <= (endPos-sizeof(ResChunk_header)) &&
3762           ((const uint8_t*)chunk) <= (endPos-dtohl(chunk->size))) {
3763        TABLE_NOISY(LOGV("PackageChunk: type=0x%x, headerSize=0x%x, size=0x%x, pos=%p\n",
3764                         dtohs(chunk->type), dtohs(chunk->headerSize), dtohl(chunk->size),
3765                         (void*)(((const uint8_t*)chunk) - ((const uint8_t*)header->header))));
3766        const size_t csize = dtohl(chunk->size);
3767        const uint16_t ctype = dtohs(chunk->type);
3768        if (ctype == RES_TABLE_TYPE_SPEC_TYPE) {
3769            const ResTable_typeSpec* typeSpec = (const ResTable_typeSpec*)(chunk);
3770            err = validate_chunk(&typeSpec->header, sizeof(*typeSpec),
3771                                 endPos, "ResTable_typeSpec");
3772            if (err != NO_ERROR) {
3773                return (mError=err);
3774            }
3775
3776            const size_t typeSpecSize = dtohl(typeSpec->header.size);
3777
3778            LOAD_TABLE_NOISY(printf("TypeSpec off %p: type=0x%x, headerSize=0x%x, size=%p\n",
3779                                    (void*)(base-(const uint8_t*)chunk),
3780                                    dtohs(typeSpec->header.type),
3781                                    dtohs(typeSpec->header.headerSize),
3782                                    (void*)typeSize));
3783            // look for block overrun or int overflow when multiplying by 4
3784            if ((dtohl(typeSpec->entryCount) > (INT32_MAX/sizeof(uint32_t))
3785                    || dtohs(typeSpec->header.headerSize)+(sizeof(uint32_t)*dtohl(typeSpec->entryCount))
3786                    > typeSpecSize)) {
3787                LOGW("ResTable_typeSpec entry index to %p extends beyond chunk end %p.",
3788                     (void*)(dtohs(typeSpec->header.headerSize)
3789                             +(sizeof(uint32_t)*dtohl(typeSpec->entryCount))),
3790                     (void*)typeSpecSize);
3791                return (mError=BAD_TYPE);
3792            }
3793
3794            if (typeSpec->id == 0) {
3795                LOGW("ResTable_type has an id of 0.");
3796                return (mError=BAD_TYPE);
3797            }
3798
3799            while (package->types.size() < typeSpec->id) {
3800                package->types.add(NULL);
3801            }
3802            Type* t = package->types[typeSpec->id-1];
3803            if (t == NULL) {
3804                t = new Type(header, package, dtohl(typeSpec->entryCount));
3805                package->types.editItemAt(typeSpec->id-1) = t;
3806            } else if (dtohl(typeSpec->entryCount) != t->entryCount) {
3807                LOGW("ResTable_typeSpec entry count inconsistent: given %d, previously %d",
3808                    (int)dtohl(typeSpec->entryCount), (int)t->entryCount);
3809                return (mError=BAD_TYPE);
3810            }
3811            t->typeSpecFlags = (const uint32_t*)(
3812                    ((const uint8_t*)typeSpec) + dtohs(typeSpec->header.headerSize));
3813            t->typeSpec = typeSpec;
3814
3815        } else if (ctype == RES_TABLE_TYPE_TYPE) {
3816            const ResTable_type* type = (const ResTable_type*)(chunk);
3817            err = validate_chunk(&type->header, sizeof(*type)-sizeof(ResTable_config)+4,
3818                                 endPos, "ResTable_type");
3819            if (err != NO_ERROR) {
3820                return (mError=err);
3821            }
3822
3823            const size_t typeSize = dtohl(type->header.size);
3824
3825            LOAD_TABLE_NOISY(printf("Type off %p: type=0x%x, headerSize=0x%x, size=%p\n",
3826                                    (void*)(base-(const uint8_t*)chunk),
3827                                    dtohs(type->header.type),
3828                                    dtohs(type->header.headerSize),
3829                                    (void*)typeSize));
3830            if (dtohs(type->header.headerSize)+(sizeof(uint32_t)*dtohl(type->entryCount))
3831                > typeSize) {
3832                LOGW("ResTable_type entry index to %p extends beyond chunk end %p.",
3833                     (void*)(dtohs(type->header.headerSize)
3834                             +(sizeof(uint32_t)*dtohl(type->entryCount))),
3835                     (void*)typeSize);
3836                return (mError=BAD_TYPE);
3837            }
3838            if (dtohl(type->entryCount) != 0
3839                && dtohl(type->entriesStart) > (typeSize-sizeof(ResTable_entry))) {
3840                LOGW("ResTable_type entriesStart at %p extends beyond chunk end %p.",
3841                     (void*)dtohl(type->entriesStart), (void*)typeSize);
3842                return (mError=BAD_TYPE);
3843            }
3844            if (type->id == 0) {
3845                LOGW("ResTable_type has an id of 0.");
3846                return (mError=BAD_TYPE);
3847            }
3848
3849            while (package->types.size() < type->id) {
3850                package->types.add(NULL);
3851            }
3852            Type* t = package->types[type->id-1];
3853            if (t == NULL) {
3854                t = new Type(header, package, dtohl(type->entryCount));
3855                package->types.editItemAt(type->id-1) = t;
3856            } else if (dtohl(type->entryCount) != t->entryCount) {
3857                LOGW("ResTable_type entry count inconsistent: given %d, previously %d",
3858                    (int)dtohl(type->entryCount), (int)t->entryCount);
3859                return (mError=BAD_TYPE);
3860            }
3861
3862            TABLE_GETENTRY(
3863                ResTable_config thisConfig;
3864                thisConfig.copyFromDtoH(type->config);
3865                LOGI("Adding config to type %d: imsi:%d/%d lang:%c%c cnt:%c%c "
3866                     "orien:%d touch:%d density:%d key:%d inp:%d nav:%d w:%d h:%d\n",
3867                      type->id,
3868                      thisConfig.mcc, thisConfig.mnc,
3869                      thisConfig.language[0] ? thisConfig.language[0] : '-',
3870                      thisConfig.language[1] ? thisConfig.language[1] : '-',
3871                      thisConfig.country[0] ? thisConfig.country[0] : '-',
3872                      thisConfig.country[1] ? thisConfig.country[1] : '-',
3873                      thisConfig.orientation,
3874                      thisConfig.touchscreen,
3875                      thisConfig.density,
3876                      thisConfig.keyboard,
3877                      thisConfig.inputFlags,
3878                      thisConfig.navigation,
3879                      thisConfig.screenWidth,
3880                      thisConfig.screenHeight));
3881            t->configs.add(type);
3882        } else {
3883            status_t err = validate_chunk(chunk, sizeof(ResChunk_header),
3884                                          endPos, "ResTable_package:unknown");
3885            if (err != NO_ERROR) {
3886                return (mError=err);
3887            }
3888        }
3889        chunk = (const ResChunk_header*)
3890            (((const uint8_t*)chunk) + csize);
3891    }
3892
3893    if (group->typeCount == 0) {
3894        group->typeCount = package->types.size();
3895    }
3896
3897    return NO_ERROR;
3898}
3899
3900#ifndef HAVE_ANDROID_OS
3901#define CHAR16_TO_CSTR(c16, len) (String8(String16(c16,len)).string())
3902
3903#define CHAR16_ARRAY_EQ(constant, var, len) \
3904        ((len == (sizeof(constant)/sizeof(constant[0]))) && (0 == memcmp((var), (constant), (len))))
3905
3906void print_complex(uint32_t complex, bool isFraction)
3907{
3908    const float MANTISSA_MULT =
3909        1.0f / (1<<Res_value::COMPLEX_MANTISSA_SHIFT);
3910    const float RADIX_MULTS[] = {
3911        1.0f*MANTISSA_MULT, 1.0f/(1<<7)*MANTISSA_MULT,
3912        1.0f/(1<<15)*MANTISSA_MULT, 1.0f/(1<<23)*MANTISSA_MULT
3913    };
3914
3915    float value = (complex&(Res_value::COMPLEX_MANTISSA_MASK
3916                   <<Res_value::COMPLEX_MANTISSA_SHIFT))
3917            * RADIX_MULTS[(complex>>Res_value::COMPLEX_RADIX_SHIFT)
3918                            & Res_value::COMPLEX_RADIX_MASK];
3919    printf("%f", value);
3920
3921    if (!isFraction) {
3922        switch ((complex>>Res_value::COMPLEX_UNIT_SHIFT)&Res_value::COMPLEX_UNIT_MASK) {
3923            case Res_value::COMPLEX_UNIT_PX: printf("px"); break;
3924            case Res_value::COMPLEX_UNIT_DIP: printf("dp"); break;
3925            case Res_value::COMPLEX_UNIT_SP: printf("sp"); break;
3926            case Res_value::COMPLEX_UNIT_PT: printf("pt"); break;
3927            case Res_value::COMPLEX_UNIT_IN: printf("in"); break;
3928            case Res_value::COMPLEX_UNIT_MM: printf("mm"); break;
3929            default: printf(" (unknown unit)"); break;
3930        }
3931    } else {
3932        switch ((complex>>Res_value::COMPLEX_UNIT_SHIFT)&Res_value::COMPLEX_UNIT_MASK) {
3933            case Res_value::COMPLEX_UNIT_FRACTION: printf("%%"); break;
3934            case Res_value::COMPLEX_UNIT_FRACTION_PARENT: printf("%%p"); break;
3935            default: printf(" (unknown unit)"); break;
3936        }
3937    }
3938}
3939
3940void ResTable::print_value(const Package* pkg, const Res_value& value) const
3941{
3942    if (value.dataType == Res_value::TYPE_NULL) {
3943        printf("(null)\n");
3944    } else if (value.dataType == Res_value::TYPE_REFERENCE) {
3945        printf("(reference) 0x%08x\n", value.data);
3946    } else if (value.dataType == Res_value::TYPE_ATTRIBUTE) {
3947        printf("(attribute) 0x%08x\n", value.data);
3948    } else if (value.dataType == Res_value::TYPE_STRING) {
3949        size_t len;
3950        const char16_t* str = pkg->header->values.stringAt(
3951                value.data, &len);
3952        if (str == NULL) {
3953            printf("(string) null\n");
3954        } else {
3955            printf("(string) \"%s\"\n",
3956                    String8(str, len).string());
3957        }
3958    } else if (value.dataType == Res_value::TYPE_FLOAT) {
3959        printf("(float) %g\n", *(const float*)&value.data);
3960    } else if (value.dataType == Res_value::TYPE_DIMENSION) {
3961        printf("(dimension) ");
3962        print_complex(value.data, false);
3963        printf("\n");
3964    } else if (value.dataType == Res_value::TYPE_FRACTION) {
3965        printf("(fraction) ");
3966        print_complex(value.data, true);
3967        printf("\n");
3968    } else if (value.dataType >= Res_value::TYPE_FIRST_COLOR_INT
3969            || value.dataType <= Res_value::TYPE_LAST_COLOR_INT) {
3970        printf("(color) #%08x\n", value.data);
3971    } else if (value.dataType == Res_value::TYPE_INT_BOOLEAN) {
3972        printf("(boolean) %s\n", value.data ? "true" : "false");
3973    } else if (value.dataType >= Res_value::TYPE_FIRST_INT
3974            || value.dataType <= Res_value::TYPE_LAST_INT) {
3975        printf("(int) 0x%08x or %d\n", value.data, value.data);
3976    } else {
3977        printf("(unknown type) t=0x%02x d=0x%08x (s=0x%04x r=0x%02x)\n",
3978               (int)value.dataType, (int)value.data,
3979               (int)value.size, (int)value.res0);
3980    }
3981}
3982
3983void ResTable::print(bool inclValues) const
3984{
3985    if (mError != 0) {
3986        printf("mError=0x%x (%s)\n", mError, strerror(mError));
3987    }
3988#if 0
3989    printf("mParams=%c%c-%c%c,\n",
3990            mParams.language[0], mParams.language[1],
3991            mParams.country[0], mParams.country[1]);
3992#endif
3993    size_t pgCount = mPackageGroups.size();
3994    printf("Package Groups (%d)\n", (int)pgCount);
3995    for (size_t pgIndex=0; pgIndex<pgCount; pgIndex++) {
3996        const PackageGroup* pg = mPackageGroups[pgIndex];
3997        printf("Package Group %d id=%d packageCount=%d name=%s\n",
3998                (int)pgIndex, pg->id, (int)pg->packages.size(),
3999                String8(pg->name).string());
4000
4001        size_t pkgCount = pg->packages.size();
4002        for (size_t pkgIndex=0; pkgIndex<pkgCount; pkgIndex++) {
4003            const Package* pkg = pg->packages[pkgIndex];
4004            size_t typeCount = pkg->types.size();
4005            printf("  Package %d id=%d name=%s typeCount=%d\n", (int)pkgIndex,
4006                    pkg->package->id, String8(String16(pkg->package->name)).string(),
4007                    (int)typeCount);
4008            for (size_t typeIndex=0; typeIndex<typeCount; typeIndex++) {
4009                const Type* typeConfigs = pkg->getType(typeIndex);
4010                if (typeConfigs == NULL) {
4011                    printf("    type %d NULL\n", (int)typeIndex);
4012                    continue;
4013                }
4014                const size_t NTC = typeConfigs->configs.size();
4015                printf("    type %d configCount=%d entryCount=%d\n",
4016                       (int)typeIndex, (int)NTC, (int)typeConfigs->entryCount);
4017                if (typeConfigs->typeSpecFlags != NULL) {
4018                    for (size_t entryIndex=0; entryIndex<typeConfigs->entryCount; entryIndex++) {
4019                        uint32_t resID = (0xff000000 & ((pkg->package->id)<<24))
4020                                    | (0x00ff0000 & ((typeIndex+1)<<16))
4021                                    | (0x0000ffff & (entryIndex));
4022                        resource_name resName;
4023                        this->getResourceName(resID, &resName);
4024                        printf("      spec resource 0x%08x %s:%s/%s: flags=0x%08x\n",
4025                            resID,
4026                            CHAR16_TO_CSTR(resName.package, resName.packageLen),
4027                            CHAR16_TO_CSTR(resName.type, resName.typeLen),
4028                            CHAR16_TO_CSTR(resName.name, resName.nameLen),
4029                            dtohl(typeConfigs->typeSpecFlags[entryIndex]));
4030                    }
4031                }
4032                for (size_t configIndex=0; configIndex<NTC; configIndex++) {
4033                    const ResTable_type* type = typeConfigs->configs[configIndex];
4034                    if ((((uint64_t)type)&0x3) != 0) {
4035                        printf("      NON-INTEGER ResTable_type ADDRESS: %p\n", type);
4036                        continue;
4037                    }
4038                    char density[16];
4039                    uint16_t dval = dtohs(type->config.density);
4040                    if (dval == ResTable_config::DENSITY_DEFAULT) {
4041                        strcpy(density, "def");
4042                    } else if (dval == ResTable_config::DENSITY_NONE) {
4043                        strcpy(density, "no");
4044                    } else {
4045                        sprintf(density, "%d", (int)dval);
4046                    }
4047                    printf("      config %d lang=%c%c cnt=%c%c orien=%d touch=%d density=%s key=%d infl=%d nav=%d w=%d h=%d sz=%d lng=%d\n",
4048                           (int)configIndex,
4049                           type->config.language[0] ? type->config.language[0] : '-',
4050                           type->config.language[1] ? type->config.language[1] : '-',
4051                           type->config.country[0] ? type->config.country[0] : '-',
4052                           type->config.country[1] ? type->config.country[1] : '-',
4053                           type->config.orientation,
4054                           type->config.touchscreen,
4055                           density,
4056                           type->config.keyboard,
4057                           type->config.inputFlags,
4058                           type->config.navigation,
4059                           dtohs(type->config.screenWidth),
4060                           dtohs(type->config.screenHeight),
4061                           type->config.screenLayout&ResTable_config::MASK_SCREENSIZE,
4062                           type->config.screenLayout&ResTable_config::MASK_SCREENLONG);
4063                    size_t entryCount = dtohl(type->entryCount);
4064                    uint32_t entriesStart = dtohl(type->entriesStart);
4065                    if ((entriesStart&0x3) != 0) {
4066                        printf("      NON-INTEGER ResTable_type entriesStart OFFSET: %p\n", (void*)entriesStart);
4067                        continue;
4068                    }
4069                    uint32_t typeSize = dtohl(type->header.size);
4070                    if ((typeSize&0x3) != 0) {
4071                        printf("      NON-INTEGER ResTable_type header.size: %p\n", (void*)typeSize);
4072                        continue;
4073                    }
4074                    for (size_t entryIndex=0; entryIndex<entryCount; entryIndex++) {
4075
4076                        const uint8_t* const end = ((const uint8_t*)type)
4077                            + dtohl(type->header.size);
4078                        const uint32_t* const eindex = (const uint32_t*)
4079                            (((const uint8_t*)type) + dtohs(type->header.headerSize));
4080
4081                        uint32_t thisOffset = dtohl(eindex[entryIndex]);
4082                        if (thisOffset == ResTable_type::NO_ENTRY) {
4083                            continue;
4084                        }
4085
4086                        uint32_t resID = (0xff000000 & ((pkg->package->id)<<24))
4087                                    | (0x00ff0000 & ((typeIndex+1)<<16))
4088                                    | (0x0000ffff & (entryIndex));
4089                        resource_name resName;
4090                        this->getResourceName(resID, &resName);
4091                        printf("        resource 0x%08x %s:%s/%s: ", resID,
4092                                CHAR16_TO_CSTR(resName.package, resName.packageLen),
4093                                CHAR16_TO_CSTR(resName.type, resName.typeLen),
4094                                CHAR16_TO_CSTR(resName.name, resName.nameLen));
4095                        if ((thisOffset&0x3) != 0) {
4096                            printf("NON-INTEGER OFFSET: %p\n", (void*)thisOffset);
4097                            continue;
4098                        }
4099                        if ((thisOffset+sizeof(ResTable_entry)) > typeSize) {
4100                            printf("OFFSET OUT OF BOUNDS: %p+%p (size is %p)\n",
4101                                   (void*)entriesStart, (void*)thisOffset,
4102                                   (void*)typeSize);
4103                            continue;
4104                        }
4105
4106                        const ResTable_entry* ent = (const ResTable_entry*)
4107                            (((const uint8_t*)type) + entriesStart + thisOffset);
4108                        if (((entriesStart + thisOffset)&0x3) != 0) {
4109                            printf("NON-INTEGER ResTable_entry OFFSET: %p\n",
4110                                 (void*)(entriesStart + thisOffset));
4111                            continue;
4112                        }
4113
4114                        uint16_t esize = dtohs(ent->size);
4115                        if ((esize&0x3) != 0) {
4116                            printf("NON-INTEGER ResTable_entry SIZE: %p\n", (void*)esize);
4117                            continue;
4118                        }
4119                        if ((thisOffset+esize) > typeSize) {
4120                            printf("ResTable_entry OUT OF BOUNDS: %p+%p+%p (size is %p)\n",
4121                                   (void*)entriesStart, (void*)thisOffset,
4122                                   (void*)esize, (void*)typeSize);
4123                            continue;
4124                        }
4125
4126                        const Res_value* valuePtr = NULL;
4127                        const ResTable_map_entry* bagPtr = NULL;
4128                        Res_value value;
4129                        if ((dtohs(ent->flags)&ResTable_entry::FLAG_COMPLEX) != 0) {
4130                            printf("<bag>");
4131                            bagPtr = (const ResTable_map_entry*)ent;
4132                        } else {
4133                            valuePtr = (const Res_value*)
4134                                (((const uint8_t*)ent) + esize);
4135                            value.copyFrom_dtoh(*valuePtr);
4136                            printf("t=0x%02x d=0x%08x (s=0x%04x r=0x%02x)",
4137                                   (int)value.dataType, (int)value.data,
4138                                   (int)value.size, (int)value.res0);
4139                        }
4140
4141                        if ((dtohs(ent->flags)&ResTable_entry::FLAG_PUBLIC) != 0) {
4142                            printf(" (PUBLIC)");
4143                        }
4144                        printf("\n");
4145
4146                        if (inclValues) {
4147                            if (valuePtr != NULL) {
4148                                printf("          ");
4149                                print_value(pkg, value);
4150                            } else if (bagPtr != NULL) {
4151                                const int N = dtohl(bagPtr->count);
4152                                const ResTable_map* mapPtr = (const ResTable_map*)
4153                                        (((const uint8_t*)ent) + esize);
4154                                printf("          Parent=0x%08x, Count=%d\n",
4155                                    dtohl(bagPtr->parent.ident), N);
4156                                for (int i=0; i<N; i++) {
4157                                    printf("          #%i (Key=0x%08x): ",
4158                                        i, dtohl(mapPtr->name.ident));
4159                                    value.copyFrom_dtoh(mapPtr->value);
4160                                    print_value(pkg, value);
4161                                    const size_t size = dtohs(mapPtr->value.size);
4162                                    mapPtr = (ResTable_map*)(((const uint8_t*)mapPtr)
4163                                            + size + sizeof(*mapPtr)-sizeof(mapPtr->value));
4164                                }
4165                            }
4166                        }
4167                    }
4168                }
4169            }
4170        }
4171    }
4172}
4173
4174#endif // HAVE_ANDROID_OS
4175
4176}   // namespace android
4177